summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in33
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/acm.c38
-rw-r--r--drivers/usb/audio.c62
-rw-r--r--drivers/usb/audio.h2
-rw-r--r--drivers/usb/cpia.c1425
-rw-r--r--drivers/usb/cpia.h205
-rw-r--r--drivers/usb/devices.c3
-rw-r--r--drivers/usb/devio.c2
-rw-r--r--drivers/usb/drivers.c4
-rw-r--r--drivers/usb/evdev.c122
-rw-r--r--drivers/usb/hid.c2
-rw-r--r--drivers/usb/hub.c30
-rw-r--r--drivers/usb/ibmcam.c39
-rw-r--r--drivers/usb/inode.c3
-rw-r--r--drivers/usb/input.c155
-rw-r--r--drivers/usb/joydev.c91
-rw-r--r--drivers/usb/keybdev.c131
-rw-r--r--drivers/usb/mdc800.c74
-rw-r--r--drivers/usb/mousedev.c312
-rw-r--r--drivers/usb/ov511.c663
-rw-r--r--drivers/usb/ov511.h63
-rw-r--r--drivers/usb/pegasus.c53
-rw-r--r--drivers/usb/printer.c10
-rw-r--r--drivers/usb/scanner.c125
-rw-r--r--drivers/usb/scanner.h7
-rw-r--r--drivers/usb/serial/Makefile62
-rw-r--r--drivers/usb/serial/ezusb_convert.pl4
-rw-r--r--drivers/usb/serial/ftdi_sio.c728
-rw-r--r--drivers/usb/serial/ftdi_sio.h573
-rw-r--r--drivers/usb/serial/keyspan_pda.c717
-rw-r--r--drivers/usb/serial/usb-serial.c2593
-rw-r--r--drivers/usb/serial/usb-serial.h376
-rw-r--r--drivers/usb/serial/usbserial.c1323
-rw-r--r--drivers/usb/serial/visor.c209
-rw-r--r--drivers/usb/serial/visor.h74
-rw-r--r--drivers/usb/serial/whiteheat.c251
-rw-r--r--drivers/usb/serial/whiteheat_fw.h (renamed from drivers/usb/serial/whiteheat.h)1552
-rw-r--r--drivers/usb/uhci.c404
-rw-r--r--drivers/usb/uhci.h31
-rw-r--r--drivers/usb/usb-core.c5
-rw-r--r--drivers/usb/usb-debug.c7
-rw-r--r--drivers/usb/usb-ohci.c348
-rw-r--r--drivers/usb/usb-storage.c1279
-rw-r--r--drivers/usb/usb-storage.h8
-rw-r--r--drivers/usb/usb-uhci.c73
-rw-r--r--drivers/usb/usb-uhci.h9
-rw-r--r--drivers/usb/usb.c63
-rw-r--r--drivers/usb/usbdevice_fs.h170
49 files changed, 7048 insertions, 7468 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 28ad96481..460a44105 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -6,6 +6,10 @@ comment 'USB support'
tristate 'Support for USB' CONFIG_USB
if [ ! "$CONFIG_USB" = "n" ]; then
+ bool ' USB verbose debug messages' CONFIG_USB_DEBUG
+
+comment 'Miscellaneous USB options'
+ bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
comment 'USB Controllers'
if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
@@ -13,19 +17,13 @@ comment 'USB Controllers'
fi
if [ "$CONFIG_USB_UHCI" != "y" ]; then
dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
- if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
- fi
fi
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
-comment 'Miscellaneous USB options'
- bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
-
comment 'USB Devices'
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
- dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
+ dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
if [ "$CONFIG_USB_SERIAL" != "n" ]; then
@@ -38,9 +36,8 @@ comment 'USB Devices'
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
fi
- dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
- dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
- dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
+ dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
@@ -52,12 +49,12 @@ comment 'USB Devices'
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB
- dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB
+ dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
+ dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
- dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
fi
-
+
comment 'USB HID'
dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
if [ "$CONFIG_USB_HID" != "y" ]; then
@@ -69,12 +66,8 @@ comment 'USB HID'
dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
- bool ' Mix all mice into one device' CONFIG_INPUT_MOUSEDEV_MIX
- bool ' Support for digitizers' CONFIG_INPUT_MOUSEDEV_DIGITIZER
- if [ "$CONFIG_INPUT_MOUSEDEV_DIGITIZER" != "n" ]; then
- int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
- int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
- fi
+ int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+ int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi
dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 06b0a4648..f0ca0476e 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -42,7 +42,7 @@ obj- :=
ifeq ($(CONFIG_USB_SERIAL),y)
SUB_DIRS += serial
- obj-y += serial/serial.o
+ obj-y += serial/usb-serial.o
else
ifeq ($(CONFIG_USB_SERIAL),m)
MOD_IN_SUB_DIRS += serial
@@ -71,7 +71,6 @@ obj-$(CONFIG_USB_SCANNER) += scanner.o
obj-$(CONFIG_USB_ACM) += acm.o
obj-$(CONFIG_USB_PRINTER) += printer.o
obj-$(CONFIG_USB_AUDIO) += audio.o
-obj-$(CONFIG_USB_CPIA) += cpia.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
obj-$(CONFIG_USB_MDC800) += mdc800.o
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 723ceb481..453c4af19 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -52,6 +52,10 @@
#define DEBUG
#include <linux/usb.h>
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned minor);
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
/*
* CMSPAR, some architectures can't have space and mark parity.
*/
@@ -143,6 +147,7 @@ struct acm {
};
static struct usb_driver acm_driver;
+static struct tty_driver acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
#define ACM_READY(acm) (acm && acm->dev && acm->used)
@@ -306,20 +311,19 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (!acm || !acm->used) return;
- MOD_DEC_USE_COUNT;
-
- if (--acm->used) return;
-
- if (acm->dev) {
- acm_set_control(acm, acm->ctrlout = 0);
- usb_unlink_urb(&acm->ctrlurb);
- usb_unlink_urb(&acm->writeurb);
- usb_unlink_urb(&acm->readurb);
- return;
+ if (!--acm->used) {
+ if (acm->dev) {
+ acm_set_control(acm, acm->ctrlout = 0);
+ usb_unlink_urb(&acm->ctrlurb);
+ usb_unlink_urb(&acm->writeurb);
+ usb_unlink_urb(&acm->readurb);
+ } else {
+ tty_unregister_devfs(&acm_tty_driver, acm->minor);
+ acm_table[acm->minor] = NULL;
+ kfree(acm);
+ }
}
-
- acm_table[acm->minor] = NULL;
- kfree(acm);
+ MOD_DEC_USE_COUNT;
}
static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
@@ -572,6 +576,7 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+ tty_register_devfs(&acm_tty_driver, 0, minor);
return acm_table[minor] = acm;
}
@@ -599,6 +604,7 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
usb_driver_release_interface(&acm_driver, acm->iface + 1);
if (!acm->used) {
+ tty_unregister_devfs(&acm_tty_driver, acm->minor);
acm_table[acm->minor] = NULL;
kfree(acm);
return;
@@ -630,14 +636,14 @@ static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
static struct tty_driver acm_tty_driver = {
magic: TTY_DRIVER_MAGIC,
- driver_name: "usb",
- name: "ttyACM",
+ driver_name: "acm",
+ name: "usb/acm/%d",
major: ACM_TTY_MAJOR,
minor_start: 0,
num: ACM_TTY_MINORS,
type: TTY_DRIVER_TYPE_SERIAL,
subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW,
+ flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
refcount: &acm_tty_refcount,
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index ad2f666d5..6772889b0 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -1395,25 +1395,30 @@ static int usbout_start(struct usb_audiodev *as)
/* --------------------------------------------------------------------- */
-static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt)
+static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate)
{
unsigned int i;
- /* first find an exact match */
- for (i = 0; i < nr; i++)
- if (afp[i].format == fmt)
+ /* first find an exact match, taking both format and sample rate into account,
+ but ignore stereo bit */
+ for (i = 0; i < nr; i++) {
+ if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
+ }
+
/* second find a match with the same stereo/mono and 8bit/16bit property */
for (i = 0; i < nr; i++)
if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
- !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt))
+ !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) &&
+ rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
/* third find a match with the same number of channels */
for (i = 0; i < nr; i++)
- if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt))
+ if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
+ rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
- /* return anything */
- return 0;
+ /* return failure */
+ return -1;
}
static int set_format_in(struct usb_audiodev *as)
@@ -1432,7 +1437,13 @@ static int set_format_in(struct usb_audiodev *as)
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
iface = &config->interface[u->interface];
- fmtnr = find_format(as->fmtin, as->numfmtin, d->format);
+
+ fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
+ if (fmtnr < 0) {
+ printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
+ return -1;
+ }
+
fmt = as->fmtin + fmtnr;
alts = &iface->altsetting[fmt->altsetting];
u->format = fmt->format;
@@ -1513,7 +1524,13 @@ static int set_format_out(struct usb_audiodev *as)
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
iface = &config->interface[u->interface];
- fmtnr = find_format(as->fmtout, as->numfmtout, d->format);
+
+ fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
+ if (fmtnr < 0) {
+ printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
+ return -1;
+ }
+
fmt = as->fmtout + fmtnr;
u->format = fmt->format;
alts = &iface->altsetting[fmt->altsetting];
@@ -3330,7 +3347,7 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
struct usb_interface *iface;
unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
unsigned char *p1;
- unsigned int i, j, numifin = 0, numifout = 0;
+ unsigned int i, j, k, numifin = 0, numifout = 0;
if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
return NULL;
@@ -3377,12 +3394,25 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
dev->devnum, ctrlif, j);
continue;
}
- if (iface->num_altsetting < 2 ||
- iface->altsetting[0].bNumEndpoints > 0) {
- printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u altsetting 0 not zero bandwidth\n",
- dev->devnum, ctrlif);
+ if (iface->num_altsetting == 0) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif);
+ continue;
+ }
+ if (iface->num_altsetting == 1) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
continue;
}
+ if (iface->altsetting[0].bNumEndpoints > 0) {
+ /* Check all endpoints; should they all have a bandwidth of 0 ? */
+ for (k = 0; k < iface->altsetting[0].bNumEndpoints; k++) {
+ if (iface->altsetting[0].endpoint[k].wMaxPacketSize > 0) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
+ break;
+ }
+ }
+ if (k < iface->altsetting[0].bNumEndpoints)
+ continue;
+ }
if (iface->altsetting[1].bNumEndpoints < 1) {
printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
dev->devnum, ctrlif, j);
@@ -3418,7 +3448,7 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
}
- ret:
+ret:
if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
kfree(s);
return NULL;
diff --git a/drivers/usb/audio.h b/drivers/usb/audio.h
index a0ecb51ee..bb51e468b 100644
--- a/drivers/usb/audio.h
+++ b/drivers/usb/audio.h
@@ -30,7 +30,7 @@
#define MAX_FREQ 16
#define MAX_IFACE 8
#define MAX_FORMAT 8
-#define MAX_ALT 8
+#define MAX_ALT 32 /* Sorry, we need quite a few for the Philips webcams */
struct usb_audio_terminal
{
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
deleted file mode 100644
index 510e8297f..000000000
--- a/drivers/usb/cpia.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- * USB CPiA Video Camera driver
- *
- * Supports CPiA based Video Cameras. Many manufacturers use this chipset.
- *
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
- * (C) Copyright 1999 Randy Dunlap
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <asm/io.h>
-
-#include "cpia.h"
-
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-/* Video Size 384 x 288 x 3 bytes for RGB */
-/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x) do { } while(0) /* Debug memory management */
-
-static struct usb_driver cpia_driver;
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
- unsigned long ret = 0UL;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- if (!pgd_none(*pgd)) {
- pmd = pmd_offset(pgd, adr);
- if (!pmd_none(*pmd)) {
- ptep = pte_offset(pmd, adr);
- pte = *ptep;
- if (pte_present(pte))
- ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
- }
- }
- MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = __pa(kva);
- MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr, page;
-
- /* Round it off to PAGE_SIZE */
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- mem = vmalloc(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- page = kvirt_to_pa(adr);
- mem_map_reserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr, page;
-
- if (!mem)
- return;
-
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- adr=(unsigned long) mem;
- while (size > 0) {
- page = kvirt_to_pa(adr);
- mem_map_unreserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- vfree(mem);
-}
-
-static int usb_cpia_get_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_PNP_ID,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 6, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_CAMERA_STATUS,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 8, HZ);
-}
-#endif
-
-static int usb_cpia_goto_hi_power(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VP_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_SENSOR_FPS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- streamstartline << 8, 0, NULL, 0, HZ);
-}
-#endif
-
-static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- forceupload, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_GRAB_MODE,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
- 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_FORMAT,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (subsample << 8) + size, order, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_ROI,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (colend << 8) + colstart, (rowend << 8) + rowstart,
- NULL, 0, HZ);
-}
-
-static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (decimation << 8) + compmode, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_set_compression_target(struct usb_device *dev, int target, int targetfr, int targetq)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION_TARGET,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (targetfr << 8) + target, targetq, NULL, 0, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_INIT_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_finistreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_FINI_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_startstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_START_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_endstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_END_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-#endif
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
-
-static void cpia_parse_data(struct usb_cpia *cpia)
-{
- struct cpia_frame *frame, *pframe;
- unsigned char *data = cpia->scratch;
- unsigned long left;
- long copylen = 0;
-
- /* Grab the current frame and the previous frame */
- frame = &cpia->frame[cpia->curframe];
- pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
-
- while (1) {
- if (!scratch_left(data))
- goto out;
-
- switch (frame->scanstate) {
- case STATE_SCANNING:
- {
- struct cpia_frame_header *header;
-
- /* We need at least 2 bytes for the magic value */
- if (scratch_left(data) < 2)
- goto out;
-
- header = (struct cpia_frame_header *)data;
-
- if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
- frame->scanstate = STATE_HEADER;
- break;
- }
-
- /* Woops, lost the header, find the end of the frame */
- if (scratch_left(data) < 4)
- goto out;
-
- /* See if we found the end of the frame */
- while (scratch_left(data) >= 4) {
- if (*((__u32 *)data) == 0xFFFFFFFF) {
- data += 4;
- if (debug >= 1)
- printk(KERN_INFO "cpia: EOF while scanning for magic\n");
- goto error;
- }
- data++;
- }
- break;
- }
- case STATE_HEADER:
- /* We need at least 64 bytes for the header */
- if (scratch_left(data) <
- sizeof(struct cpia_frame_header))
- goto out;
-
- memcpy(&frame->header, data,
- sizeof(struct cpia_frame_header));
-
- /* Skip over the header */
- data += sizeof(struct cpia_frame_header);
-
- frame->hdrwidth = (frame->header.col_end -
- frame->header.col_start) * 8;
- frame->hdrheight = (frame->header.row_end -
- frame->header.row_start) * 4;
- if (debug >= 2) {
- printk(KERN_DEBUG "cpia: frame size %dx%d\n",
- frame->hdrwidth, frame->hdrheight);
- printk(KERN_DEBUG "cpia: frame %scompressed\n",
- frame->header.comp_enable ? "" : "not ");
- }
-
- frame->scanstate = STATE_LINES;
- frame->curline = 0;
- break;
-
- case STATE_LINES:
- {
- unsigned char *f, *end;
- unsigned int len;
- int i;
- int y, u, y1, v, r, g, b;
-
- /* We want at least 2 bytes for the length */
- if (scratch_left(data) < 2)
- goto out;
-
- /* Grab the length */
- len = data[0] + (data[1] << 8);
-
- /* Check to make sure it's nothing outrageous */
- if (len > (frame->hdrwidth * 2) + 1) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: bad length, resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len);
- goto error;
- }
-
- /* Make sure there's enough data for the entire line */
- if (scratch_left(data + 2) < len)
- goto out;
-
- /* Skip over the length */
- data += 2;
-
- /* Is the end of the line there */
- if (data[len - 1] != 0xFD) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: lost synch\n");
- goto error;
- }
-
- /* Start at the beginning */
- end = data + len - 1;
-
- f = frame->data + (frame->width * 3 * frame->curline);
-
- if (frame->header.comp_enable) {
- unsigned char *fp;
-
- /* We use the previous frame as a reference */
- fp = pframe->data +
- (frame->width * 3 * frame->curline);
-
- while (data < end) {
- if (*data & 1) {
- /* Compress RLE data */
- i = *data >> 1;
- memcpy(f, fp, i * 3);
- copylen += (i * 3);
- f += (i * 3);
- fp += (i * 3);
- data++;
- } else {
- /* Raw data */
-
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
- fp += 6;
- copylen += 6;
- }
- }
- } else {
- /* Raw data */
- while (data < end) {
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-copylen += 6;
- }
- }
-
- /* Skip the last byte */
- data++;
-
- if (++frame->curline >= frame->hdrheight)
- goto nextframe;
-
- break;
- } /* end case STATE_LINES */
- } /* end switch (scanstate) */
- } /* end while (1) */
-
-nextframe:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as success\n");
-
- if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF)
- data += 4;
-
- frame->grabstate = FRAME_DONE;
-
- goto wakeup;
-
-error:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as error\n");
-
- frame->grabstate = FRAME_ERROR;
-
- /* Get a fresh frame since this frame may have been important */
- cpia->compress = 0;
-
- copylen = 0;
-
-wakeup:
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&frame->wq))
- wake_up_interruptible(&frame->wq);
-
-out:
- /* Grab the remaining */
- left = scratch_left(data);
- memmove(cpia->scratch, data, left);
- cpia->scratchlen = left;
-
- /* Update the frame's uncompressed length. */
- frame->scanlength += copylen;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int cpia_compress_isochronous(struct usb_cpia *cpia, urb_t *urb)
-{
- unsigned char *cdata, *data;
- int i, totlen = 0;
-
- data = cpia->scratch + cpia->scratchlen;
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st && debug >= 1)
- printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
- i, n, st);
-
- if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
- printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n",cpia->scratchlen, n );
- return totlen;
- }
-
- if (n) {
- memmove(data, cdata, n);
- data += n;
- totlen += n;
- cpia->scratchlen += n;
- }
- }
-
- return totlen;
-}
-
-static void cpia_isoc_irq(struct urb *urb)
-{
- int len;
- struct usb_cpia *cpia = urb->context;
- struct cpia_sbuf *sbuf;
- int i;
-
- if (!cpia->dev)
- return;
-
- if (!cpia->streaming) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: oops, not streaming, but interrupt\n");
- return;
- }
-
- sbuf = &cpia->sbuf[cpia->cursbuf];
-
- /* Copy the data received into our scratch buffer */
- len = cpia_compress_isochronous(cpia, urb);
-
- /* If we don't have a frame we're current working on, complain */
- if (cpia->scratchlen) {
- if (cpia->curframe < 0) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: received data, but no frame available\n");
- } else
- cpia_parse_data(cpia);
- }
-
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- sbuf->urb->iso_frame_desc[i].status = 0;
- sbuf->urb->iso_frame_desc[i].actual_length = 0;
- }
-
- /* Move to the next sbuf */
- cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
-
- return;
-}
-
-static int cpia_init_isoc(struct usb_cpia *cpia)
-{
- urb_t *urb;
- int fx, err;
-
- cpia->compress = 0;
- cpia->curframe = -1;
- cpia->cursbuf = 0;
- cpia->scratchlen = 0;
-
- /* Alternate interface 3 is is the biggest frame size */
- if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- /* We double buffer the Iso lists */
- urb = usb_alloc_urb(FRAMES_PER_DESC);
-
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[0].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[0].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
- urb = usb_alloc_urb(FRAMES_PER_DESC);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[1].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[1].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
- cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
-
- err = usb_submit_urb(cpia->sbuf[0].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n",
- err);
- err = usb_submit_urb(cpia->sbuf[1].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n",
- err);
-
- cpia->streaming = 1;
-
- return 0;
-}
-
-static void cpia_stop_isoc(struct usb_cpia *cpia)
-{
- if (!cpia->streaming || !cpia->dev)
- return;
-
- /* Turn off continuous grab */
- if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- return /* -EBUSY */;
- }
-
- /* Set packet size to 0 */
- if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return /* -EINVAL */;
- }
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-}
-
-static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
-{
- struct cpia_frame *frame;
- int width, height;
-
- if (!cpia->dev)
- return -1;
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (cpia->curframe == -1) {
- if (cpia->frame[(framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES].grabstate == FRAME_READY)
- framenum = (framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES;
- } else
- return 0;
-
- frame = &cpia->frame[framenum];
- width = frame->width;
- height = frame->height;
-
- frame->grabstate = FRAME_GRABBING;
- frame->scanstate = STATE_SCANNING;
- frame->scanlength = 0; /* accumulated in cpia_parse_data() */
-
- cpia->curframe = framenum;
-
- /* Make sure it's not too big */
- if (width > 352)
- width = 352;
- width = (width / 8) * 8; /* Multiple of 8 */
-
- if (height > 288)
- height = 288;
- height = (height / 4) * 4; /* Multiple of 4 */
-
- /* Set the ROI they want */
- if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
- return -EBUSY;
-
- if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
- COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- return -EBUSY;
- }
-
- /* We want a fresh frame every 30 we get */
- cpia->compress = (cpia->compress + 1) % 30;
-
- /* Grab the frame */
- if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
- printk(KERN_ERR "cpia_upload_frame error\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-/* Video 4 Linux API */
-static int cpia_open(struct video_device *dev, int flags)
-{
- int err = -EBUSY;
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- if (cpia->user)
- goto out_unlock;
-
- cpia->frame[0].grabstate = FRAME_UNUSED;
- cpia->frame[1].grabstate = FRAME_UNUSED;
-
- err = -ENOMEM;
-
- /* Allocate memory for the frame buffers */
- cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
- if (!cpia->fbuf)
- goto open_err_ret;
-
- cpia->frame[0].data = cpia->fbuf;
- cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
-
- cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[0].data)
- goto open_err_on0;
-
- cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[1].data)
- goto open_err_on1;
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- cpia->frame[0].width = 352;
- cpia->frame[0].height = 288;
- cpia->frame[0].bytes_read = 0;
- cpia->frame[1].width = 352;
- cpia->frame[1].height = 288;
- cpia->frame[1].bytes_read = 0;
-
- err = cpia_init_isoc(cpia);
- if (err)
- goto open_err_on2;
-
- cpia->user++;
- up(&cpia->lock);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-
-open_err_on2:
- kfree (cpia->sbuf[1].data);
-open_err_on1:
- kfree (cpia->sbuf[0].data);
-open_err_on0:
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-open_err_ret:
- return err;
-
-out_unlock:
- up(&cpia->lock);
- return err;
-}
-
-static void cpia_close(struct video_device *dev)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- cpia->user--;
-
- MOD_DEC_USE_COUNT;
-
- cpia_stop_isoc(cpia);
-
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-
- kfree(cpia->sbuf[1].data);
- kfree(cpia->sbuf[0].data);
-
- up(&cpia->lock);
-
- if (!cpia->dev) {
- video_unregister_device(&cpia->vdev);
- kfree(cpia);
- }
-}
-
-static int cpia_init_done(struct video_device *dev)
-{
- return 0;
-}
-
-static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
-{
- return -EINVAL;
-}
-
-static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- if (!cpia->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability b;
-
- strcpy(b.name, "CPiA USB Camera");
- b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b.channels = 1;
- b.audios = 0;
- b.maxwidth = 352; /* CIF */
- b.maxheight = 288; /* " */
- b.minwidth = 8;
- b.minheight = 4;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v.channel != 0)
- return -EINVAL;
-
- v.flags = 0;
- v.tuners = 0;
- v.type = VIDEO_TYPE_CAMERA;
- strcpy(v.name, "Camera");
-
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSCHAN:
- {
- int v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v != 0)
- return -EINVAL;
-
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture p;
-
- p.colour = 0x8000; /* Damn British people :) */
- p.hue = 0x8000;
- p.brightness = 180 << 8; /* XXX */
- p.contrast = 192 << 8; /* XXX */
- p.whiteness = 105 << 8; /* XXX */
- p.depth = 24;
- p.palette = VIDEO_PALETTE_RGB24;
-
- if (copy_to_user(arg, &p, sizeof(p)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture p;
-
- if (copy_from_user(&p, arg, sizeof(p)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window vw;
-
- if (copy_from_user(&vw, arg, sizeof(vw)))
- return -EFAULT;
- if (vw.flags)
- return -EINVAL;
- if (vw.clipcount)
- return -EINVAL;
- if (vw.height != 288)
- return -EINVAL;
- if (vw.width != 352)
- return -EINVAL;
-
- cpia->compress = 0;
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window vw;
-
- vw.x = 0;
- vw.y = 0;
- vw.width = 352;
- vw.height = 288;
- vw.chromakey = 0;
- vw.flags = 30; /* 30 fps */
-
- if (copy_to_user(arg, &vw, sizeof(vw)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf vm;
-
- memset(&vm, 0, sizeof(vm));
- vm.size = MAX_FRAME_SIZE * 2;
- vm.frames = 2;
- vm.offsets[0] = 0;
- vm.offsets[1] = MAX_FRAME_SIZE;
-
- if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap vm;
-
- if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
- vm.frame, vm.width, vm.height, vm.format);
-
- if (vm.format != VIDEO_PALETTE_RGB24)
- return -EINVAL;
-
- if ((vm.frame != 0) && (vm.frame != 1))
- return -EINVAL;
-
- if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
- return -EBUSY;
-
- /* Don't compress if the size changed */
- if ((cpia->frame[vm.frame].width != vm.width) ||
- (cpia->frame[vm.frame].height != vm.height))
- cpia->compress = 0;
-
- cpia->frame[vm.frame].width = vm.width;
- cpia->frame[vm.frame].height = vm.height;
-
- /* Mark it as ready */
- cpia->frame[vm.frame].grabstate = FRAME_READY;
-
- return cpia_new_frame(cpia, vm.frame);
- }
- case VIDIOCSYNC:
- {
- int frame;
-
- if (copy_from_user((void *)&frame, arg, sizeof(int)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: syncing to frame %d\n", frame);
-
- switch (cpia->frame[frame].grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
-redo:
- if (!cpia->dev)
- return -EIO;
-
- do {
- interruptible_sleep_on(&cpia->frame[frame].wq);
- if (signal_pending(current))
- return -EINTR;
- } while (cpia->frame[frame].grabstate == FRAME_GRABBING);
-
- if (cpia->frame[frame].grabstate == FRAME_ERROR) {
- int ret;
-
- if ((ret = cpia_new_frame(cpia, frame)) < 0)
- return ret;
- goto redo;
- }
- case FRAME_DONE:
- cpia->frame[frame].grabstate = FRAME_UNUSED;
- break;
- }
-
- cpia->frame[frame].grabstate = FRAME_UNUSED;
-
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer vb;
-
- memset(&vb, 0, sizeof(vb));
- vb.base = NULL; /* frame buffer not supported, not used */
-
- if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- return -EINVAL;
- case VIDIOCSFBUF:
- return -EINVAL;
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- return -EINVAL;
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- return -EINVAL;
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- int frmx = -1;
- volatile struct cpia_frame *frame;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: %ld bytes, noblock=%d\n", count, noblock);
-
- if (!dev || !buf)
- return -EFAULT;
-
- if (!cpia->dev)
- return -EIO;
-
- /* See if a frame is completed, then use it. */
- if (cpia->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */
- frmx = 0;
- else if (cpia->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
- frmx = 1;
-
- if (noblock && (frmx == -1))
- return -EAGAIN;
-
- /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
- /* See if a frame is in process (grabbing), then use it. */
- if (frmx == -1) {
- if (cpia->frame[0].grabstate == FRAME_GRABBING)
- frmx = 0;
- else if (cpia->frame[1].grabstate == FRAME_GRABBING)
- frmx = 1;
- }
-
- /* If no frame is active, start one. */
- if (frmx == -1)
- cpia_new_frame(cpia, frmx = 0);
-
- frame = &cpia->frame[frmx];
-
-restart:
- if (!cpia->dev)
- return -EIO;
-
- while (frame->grabstate == FRAME_GRABBING) {
- interruptible_sleep_on(&frame->wq);
- if (signal_pending(current))
- return -EINTR;
- }
-
- if (frame->grabstate == FRAME_ERROR) {
- frame->bytes_read = 0;
-printk("cpia_read: errored frame %d\n", cpia->curframe);
- if (cpia_new_frame(cpia, frmx))
- printk(KERN_ERR "cpia_read: cpia_new_frame error\n");
- goto restart;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
- frmx, frame->bytes_read, frame->scanlength);
-
- /* copy bytes to user space; we allow for partials reads */
- if ((count + frame->bytes_read) > frame->scanlength)
- count = frame->scanlength - frame->bytes_read;
-
- if (copy_to_user(buf, frame->data + frame->bytes_read, count))
- return -EFAULT;
-
- frame->bytes_read += count;
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: {copy} count used=%ld, new bytes_read=%ld\n",
- count, frame->bytes_read);
-
- if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
- frame->bytes_read = 0;
-
- /* Mark it as available to be used again. */
- cpia->frame[frmx].grabstate = FRAME_UNUSED;
- if (cpia_new_frame(cpia, frmx ? 0 : 1))
- printk(KERN_ERR "cpia_read: cpia_new_frame returned error\n");
- }
-
- return count;
-}
-
-static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- unsigned long start = (unsigned long)adr;
- unsigned long page, pos;
-
- if (!cpia->dev)
- return -EIO;
-
- if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
- return -EINVAL;
-
- pos = (unsigned long)cpia->fbuf;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return 0;
-}
-
-static struct video_device cpia_template = {
- "CPiA USB Camera",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_CPIA,
- cpia_open,
- cpia_close,
- cpia_read,
- cpia_write,
- NULL,
- cpia_ioctl,
- cpia_mmap,
- cpia_init_done,
- NULL,
- 0,
- 0
-};
-
-static int usb_cpia_configure(struct usb_cpia *cpia)
-{
- struct usb_device *dev = cpia->dev;
- unsigned char version[4];
-
- /* Set altsetting 0 */
- if (usb_set_interface(dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- if (usb_cpia_get_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_version error\n");
- return -EBUSY;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
- version[0], version[1], version[2], version[3]);
-
- memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
-
- init_waitqueue_head(&cpia->frame[0].wq);
- init_waitqueue_head(&cpia->frame[1].wq);
-
- if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
- printk(KERN_ERR "video_register_device failed\n");
- return -EBUSY;
- }
-
- if (usb_cpia_goto_hi_power(dev) < 0) {
- printk(KERN_ERR "cpia_goto_hi_power error\n");
- goto error;
- }
-
- if (usb_cpia_get_vp_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_vp_version error\n");
- goto error;
- }
-
- if (debug >= 1) {
- printk(KERN_DEBUG "cpia: VP v%d rev %d\n", version[0], version[1]);
- printk(KERN_DEBUG "cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
- }
-
- /* Turn on continuous grab */
- if (usb_cpia_set_grab_mode(dev, 1) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- goto error;
- }
-
- /* Set up the sensor to be 30fps */
- if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
- printk(KERN_ERR "cpia_set_sensor_fps error\n");
- goto error;
- }
-
- /* Set video into CIF mode, and order into YUYV mode */
- if (usb_cpia_set_format(dev, FORMAT_CIF, FORMAT_422,
- FORMAT_YUYV) < 0) {
- printk(KERN_ERR "cpia_set_format error\n");
- goto error;
- }
-
- /* Turn off compression */
- if (usb_cpia_set_compression(dev, COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- goto error;
- }
-
- cpia->compress = 0;
-
- return 0;
-
-error:
- video_unregister_device(&cpia->vdev);
- usb_driver_release_interface(&cpia_driver,
- &dev->actconfig->interface[0]);
-
- kfree(cpia);
-
- return -EBUSY;
-}
-
-static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_interface_descriptor *interface;
- struct usb_cpia *cpia;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return NULL;
-
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
-
- /* Is it a CPiA? */
- if (dev->descriptor.idVendor != 0x0553)
- return NULL;
- if (dev->descriptor.idProduct != 0x0002)
- return NULL;
-
- /* Checking vendor/product should be enough, but what the hell */
- if (interface->bInterfaceClass != 0xFF)
- return NULL;
- if (interface->bInterfaceSubClass != 0x00)
- return NULL;
-
- /* We found a CPiA */
- printk(KERN_INFO "USB CPiA camera found\n");
-
- if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "couldn't kmalloc cpia struct\n");
- return NULL;
- }
-
- memset(cpia, 0, sizeof(*cpia));
-
- cpia->dev = dev;
- cpia->iface = interface->bInterfaceNumber;
-
- if (!usb_cpia_configure(cpia)) {
- cpia->user=0;
- init_MUTEX(&cpia->lock); /* to 1 == available */
-
- return cpia;
- } else
- return NULL;
-}
-
-static void cpia_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_cpia *cpia = (struct usb_cpia *) ptr;
-
- /* We don't want people trying to open up the device */
- if (!cpia->user)
- video_unregister_device(&cpia->vdev);
-
- usb_driver_release_interface(&cpia_driver,
- &cpia->dev->actconfig->interface[0]);
-
- cpia->dev = NULL;
- cpia->frame[0].grabstate = FRAME_ERROR;
- cpia->frame[1].grabstate = FRAME_ERROR;
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&cpia->frame[0].wq))
- wake_up_interruptible(&cpia->frame[0].wq);
-
- if (waitqueue_active(&cpia->frame[1].wq))
- wake_up_interruptible(&cpia->frame[1].wq);
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-
- /* Free the memory */
- if (!cpia->user)
- kfree(cpia);
-}
-
-static struct usb_driver cpia_driver = {
- "cpia",
- cpia_probe,
- cpia_disconnect,
- { NULL, NULL }
-};
-
-int usb_cpia_init(void)
-{
- return usb_register(&cpia_driver);
-}
-
-void usb_cpia_cleanup(void)
-{
- usb_deregister(&cpia_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return usb_cpia_init();
-}
-
-void cleanup_module(void)
-{
- usb_cpia_cleanup();
-}
-#endif
diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h
deleted file mode 100644
index 8a8342853..000000000
--- a/drivers/usb/cpia.h
+++ /dev/null
@@ -1,205 +0,0 @@
-#ifndef __LINUX_CPIA_H
-#define __LINUX_CPIA_H
-
-#include <linux/list.h>
-
-#define USB_REQ_CPIA_GET_VERSION 0x01
-#define USB_REQ_CPIA_GET_PNP_ID 0x02
-#define USB_REQ_CPIA_GET_CAMERA_STATUS 0x03
-#define USB_REQ_CPIA_GOTO_HI_POWER 0x04
-#define USB_REQ_CPIA_GOTO_LO_POWER 0x05
-/* No 0x06 */
-#define USB_REQ_CPIA_GOTO_SUSPEND 0x07
-#define USB_REQ_CPIA_GOTO_PASS_THROUGH 0x08
-/* No 0x09 */
-#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS 0x0A
-
-#define USB_REQ_CPIA_READ_VC_REGS 0x21
-#define USB_REQ_CPIA_WRITE_BC_REG 0x22
-#define USB_REQ_CPIA_READ_MC_PORTS 0x23
-#define USB_REQ_CPIA_WRITE_MC_PORT 0x24
-#define USB_REQ_CPIA_SET_BAUD_RATE 0x25
-#define USB_REQ_CPIA_SET_ECP_TIMING 0x26
-#define USB_REQ_CPIA_READ_IDATA 0x27
-#define USB_REQ_CPIA_WRITE_IDATA 0x28
-#define USB_REQ_CPIA_GENERIC_CALL 0x29
-#define USB_REQ_CPIA_I2CSTART 0x2A
-#define USB_REQ_CPIA_I2CSTOP 0x2B
-#define USB_REQ_CPIA_I2CWRITE 0x2C
-#define USB_REQ_CPIA_I2CREAD 0x2D
-
-#define USB_REQ_CPIA_GET_VP_VERSION 0xA1
-#define USB_REQ_CPIA_SET_COLOUR_PARAMS 0xA3
-#define USB_REQ_CPIA_SET_EXPOSURE 0xA4
-/* No 0xA5 */
-#define USB_REQ_CPIA_SET_COLOUR_BALANCE 0xA6
-#define USB_REQ_CPIA_SET_SENSOR_FPS 0xA7
-#define USB_REQ_CPIA_SET_VP_DEFAULTS 0xA8
-#define USB_REQ_CPIA_SET_APCOR 0xA9
-#define USB_REQ_CPIA_SET_FLICKER_CTRL 0xAA
-#define USB_REQ_CPIA_SET_VL_OFFSET 0xAB
-
-#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS 0xB0
-#define USB_REQ_CPIA_GET_COLOUR_BALANCE 0xB1
-#define USB_REQ_CPIA_GET_EXPOSURE 0xB2
-#define USB_REQ_CPIA_SET_SENSOR_MATRIX 0xB3
-
-#define USB_REQ_CPIA_COLOUR_BARS 0xBD
-#define USB_REQ_CPIA_READ_VP_REGS 0xBE
-#define USB_REQ_CPIA_WRITE_VP_REGS 0xBF
-
-#define USB_REQ_CPIA_GRAB_FRAME 0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
-#define WAIT_FOR_NEXT_FRAME 0
-#define FORCE_FRAME_UPLOAD 1
-#define USB_REQ_CPIA_SET_GRAB_MODE 0xC3
-#define USB_REQ_CPIA_INIT_STREAM_CAP 0xC4
-#define USB_REQ_CPIA_FINI_STREAM_CAP 0xC5
-#define USB_REQ_CPIA_START_STREAM_CAP 0xC6
-#define USB_REQ_CPIA_END_STREAM_CAP 0xC7
-#define USB_REQ_CPIA_SET_FORMAT 0xC8
-#define FORMAT_QCIF 0
-#define FORMAT_CIF 1
-#define FORMAT_YUYV 0
-#define FORMAT_UYVY 1
-#define FORMAT_420 0
-#define FORMAT_422 1
-#define USB_REQ_CPIA_SET_ROI 0xC9
-#define USB_REQ_CPIA_SET_COMPRESSION 0xCA
-#define COMP_DISABLED 0
-#define COMP_AUTO 1
-#define COMP_MANUAL 2
-#define DONT_DECIMATE 0
-#define DECIMATE 1
-#define USB_REQ_CPIA_SET_COMPRESSION_TARGET 0xCB
-#define TARGET_QUALITY 0
-#define TARGET_FRAMERATE 1
-#define USB_REQ_CPIA_SET_YUV_THRESH 0xCC
-#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS 0xCD
-#define USB_REQ_CPIA_DISCARD_FRAME 0xCE
-
-#define USB_REQ_CPIA_OUTPUT_RS232 0xE1
-#define USB_REQ_CPIA_ABORT_PROCESS 0xE4
-#define USB_REQ_CPIA_SET_DRAM_PAGE 0xE5
-#define USB_REQ_CPIA_START_DRAM_UPLOAD 0xE6
-#define USB_REQ_CPIA_START_DUMMY_STREAM 0xE8
-#define USB_REQ_CPIA_ABORT_STREAM 0xE9
-#define USB_REQ_CPIA_DOWNLOAD_DRAM 0xEA
-/* #define USB_REQ_CPIA_NULL_CMD 0x?? */
-
-#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
-/* #define STREAM_BUF_SIZE (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC) */
-
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
-
-#define FRAMES_PER_DESC 10
-#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
-
-enum {
- STATE_SCANNING, /* Scanning for start */
- STATE_HEADER, /* Parsing header */
- STATE_LINES, /* Parsing lines */
-};
-
-#define CPIA_MAGIC 0x1968
-struct cpia_frame_header {
- __u16 magic; /* 0 - 1 */
- __u16 timestamp; /* 2 - 3 */
- __u16 unused; /* 4 - 5 */
- __u16 timestamp1; /* 6 - 7 */
- __u8 unused1[8]; /* 8 - 15 */
- __u8 video_size; /* 16 0 = QCIF, 1 = CIF */
- __u8 sub_sample; /* 17 0 = 4:2:0, 1 = 4:2:2 */
- __u8 yuv_order; /* 18 0 = YUYV, 1 = UYVY */
- __u8 unused2[5]; /* 19 - 23 */
- __u8 col_start; /* 24 */
- __u8 col_end; /* 25 */
- __u8 row_start; /* 26 */
- __u8 row_end; /* 27 */
- __u8 comp_enable; /* 28 0 = non compressed, 1 = compressed */
- __u8 decimation; /* 29 0 = no decimation, 1 = decimation */
- __u8 y_thresh; /* 30 */
- __u8 uv_thresh; /* 31 */
- __u8 system_state; /* 32 */
- __u8 grab_state; /* 33 */
- __u8 stream_state; /* 34 */
- __u8 fatal_error; /* 35 */
- __u8 cmd_error; /* 36 */
- __u8 debug_flags; /* 37 */
- __u8 camera_state_7; /* 38 */
- __u8 camera_state_8; /* 39 */
- __u8 cr_achieved; /* 40 */
- __u8 fr_achieved; /* 41 */
- __u8 unused3[22]; /* 42 - 63 */
-};
-
-struct usb_device;
-
-struct cpia_sbuf {
- char *data;
- urb_t *urb;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-struct cpia_frame {
- char *data; /* Frame buffer */
-
- struct cpia_frame_header header; /* Header from stream */
-
- int width; /* Width application is expecting */
- int height; /* Height */
-
- int hdrwidth; /* Width the frame actually is */
- int hdrheight; /* Height */
-
- volatile int grabstate; /* State of grabbing */
- int scanstate; /* State of scanning */
-
- int curline; /* Line of frame we're working on */
-
- long scanlength; /* uncompressed, raw data length of frame */
- long bytes_read; /* amount of scanlength that has been read from *data */
-
- wait_queue_head_t wq; /* Processes waiting */
-};
-
-#define CPIA_NUMFRAMES 2
-#define CPIA_NUMSBUF 2
-
-struct usb_cpia {
- struct video_device vdev;
-
- /* Device structure */
- struct usb_device *dev;
-
- unsigned char iface;
-
- struct semaphore lock;
- int user; /* user count for exclusive use */
-
- int streaming; /* Are we streaming Isochronous? */
- int grabbing; /* Are we grabbing? */
-
- int compress; /* Should the next frame be compressed? */
-
- char *fbuf; /* Videodev buffer area */
-
- int curframe;
- struct cpia_frame frame[CPIA_NUMFRAMES]; /* Double buffering */
-
- int cursbuf; /* Current receiving sbuf */
- struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
-
- /* Scratch space from the Isochronous pipe */
- unsigned char scratch[SCRATCH_BUF_SIZE];
- int scratchlen;
-};
-
-#endif
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index 099d90372..874887a63 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -54,10 +54,9 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
#define MAX_TOPO_LEVEL 6
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index c28614d07..933895934 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -41,9 +41,9 @@
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
struct async {
struct list_head asynclist;
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
index 0dcc9f719..11e16b784 100644
--- a/drivers/usb/drivers.c
+++ b/drivers/usb/drivers.c
@@ -37,11 +37,9 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
-
/*****************************************************************/
/*
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 9cca9fdf6..1d42f7df0 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -29,9 +29,9 @@
*/
#define EVDEV_MINOR_BASE 64
+#define EVDEV_MINORS 32
#define EVDEV_BUFFER_SIZE 64
-#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/malloc.h>
#include <linux/module.h>
@@ -39,11 +39,12 @@
#include <linux/input.h>
struct evdev {
- char name[32];
int used;
+ int open;
+ int minor;
struct input_handle handle;
- struct miscdevice misc;
wait_queue_head_t wait;
+ devfs_handle_t devfs;
struct evdev_list *list;
};
@@ -56,8 +57,7 @@ struct evdev_list {
struct evdev_list *next;
};
-static unsigned long evdev_miscbits = 0;
-static struct evdev *evdev_base[BITS_PER_LONG];
+static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
@@ -99,10 +99,13 @@ static int evdev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->evdev->open)
+ input_close_device(&list->evdev->handle);
if (!--list->evdev->used) {
- clear_bit(list->evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
- misc_deregister(&list->evdev->misc);
+ input_unregister_minor(list->evdev->devfs);
+ evdev_table[list->evdev->minor] = NULL;
kfree(list->evdev);
}
@@ -117,23 +120,28 @@ static int evdev_open(struct inode * inode, struct file * file)
struct evdev_list *list;
int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
- if (i > BITS_PER_LONG || !test_bit(i, &evdev_miscbits))
+ if (i > EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct evdev_list));
- list->evdev = evdev_base[i];
- list->next = evdev_base[i]->list;
- evdev_base[i]->list = list;
+ list->evdev = evdev_table[i];
+ list->next = evdev_table[i]->list;
+ evdev_table[i]->list = list;
file->private_data = list;
list->evdev->used++;
- MOD_INC_USE_COUNT;
+ if (!list->evdev->open++)
+ input_open_device(&list->evdev->handle);
+
return 0;
}
@@ -193,34 +201,81 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
return 0;
}
+static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct evdev_list *list = file->private_data;
+ struct evdev *evdev = list->evdev;
+ struct input_dev *dev = evdev->handle.dev;
+
+ switch (cmd) {
+
+ case EVIOCGVERSION:
+ return put_user(EV_VERSION, (__u32 *) arg);
+ case EVIOCGID:
+ return copy_to_user(&dev->id, (void *) arg,
+ sizeof(struct input_id)) ? -EFAULT : 0;
+ default:
+
+ if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+ return -EINVAL;
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+ long *bits = NULL;
+ int len = 0;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ default: return -EINVAL;
+ }
+ len = NBITS(len) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user((void *) arg, bits, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
+ }
+ }
+ return -EINVAL;
+}
+
static struct file_operations evdev_fops = {
read: evdev_read,
write: evdev_write,
poll: evdev_poll,
open: evdev_open,
release: evdev_release,
+ ioctl: evdev_ioctl,
fasync: evdev_fasync,
};
-static int evdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct evdev *evdev;
+ int minor;
- if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
- return -1;
+ for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+ if (evdev_table[minor]) {
+ printk(KERN_ERR "evdev: no more free evdev devices\n");
+ return NULL;
+ }
+ if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+ return NULL;
memset(evdev, 0, sizeof(struct evdev));
init_waitqueue_head(&evdev->wait);
- evdev->misc.minor = ffz(evdev_miscbits);
- set_bit(evdev->misc.minor, &evdev_miscbits);
- evdev_base[evdev->misc.minor] = evdev;
-
- sprintf(evdev->name, "evdev%d", evdev->misc.minor);
- evdev->misc.name = evdev->name;
- evdev->misc.minor += EVDEV_MINOR_BASE;
- evdev->misc.fops = &evdev_fops;
+ evdev->minor = minor;
+ evdev_table[minor] = evdev;
evdev->handle.dev = dev;
evdev->handle.handler = handler;
@@ -228,24 +283,23 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev)
evdev->used = 1;
- misc_register(&evdev->misc);
- input_open_device(&evdev->handle);
+ evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
- printk("%s: Event device for input%d on misc%d - /dev/input%d\n",
- evdev->name, dev->number, evdev->misc.minor, evdev->misc.minor - EVDEV_MINOR_BASE);
+ printk("event%d: Event device for input%d\n", minor, dev->number);
- return 0;
+ return &evdev->handle;
}
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- input_close_device(handle);
+ if (evdev->open)
+ input_close_device(handle);
if (!--evdev->used) {
- clear_bit(evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
- misc_deregister(&evdev->misc);
+ input_unregister_minor(evdev->devfs);
+ evdev_table[evdev->minor] = NULL;
kfree(evdev);
}
}
@@ -254,6 +308,8 @@ static struct input_handler evdev_handler = {
event: evdev_event,
connect: evdev_connect,
disconnect: evdev_disconnect,
+ fops: &evdev_fops,
+ minor: EVDEV_MINOR_BASE,
};
static int __init evdev_init(void)
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index b8af56051..05372ef33 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -1288,7 +1288,7 @@ static void hid_init_input(struct hid_device *hid)
hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
if (k == HID_INPUT_REPORT) {
- usb_set_idle(hid->dev, hid->ifnum, report->id, 0);
+ usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
hid_read_report(hid, report);
}
}
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 8bd919d67..821dedb4a 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -6,12 +6,17 @@
* (C) Copyright 1999 Gregory P. Smith
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
#include <asm/uaccess.h>
@@ -609,5 +614,28 @@ void usb_hub_cleanup(void)
usb_deregister(&hub_driver);
} /* usb_hub_cleanup() */
+int usb_reset_device(struct usb_device *dev)
+{
+ struct usb_device *parent = dev->parent;
+ int i;
+
+ if (!parent) {
+ err("attempting to reset root hub!");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < parent->maxchild; i++) {
+ if (parent->children[i] == dev) {
+ usb_set_port_feature(parent, i + 1,
+ USB_PORT_FEAT_RESET);
+ usb_disconnect(&dev);
+ usb_hub_port_connect_change(parent, i);
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index fe93e5bcc..2deab03fa 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -58,6 +58,8 @@ typedef enum {
#define FLAGS_DISPLAY_HINTS (1 << 2)
#define FLAGS_OVERLAY_STATS (1 << 3)
#define FLAGS_FORCE_TESTPATTERN (1 << 4)
+#define FLAGS_SEPARATE_FRAMES (1 << 5)
+#define FLAGS_CLEAN_FRAMES (1 << 6)
static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
@@ -2238,6 +2240,12 @@ static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam)
}
}
+/*
+ * ibmcam_new_frame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ */
static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
{
struct ibmcam_frame *frame;
@@ -2258,10 +2266,33 @@ static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
frame->scanstate = STATE_SCANNING;
frame->scanlength = 0; /* Accumulated in ibmcam_parse_data() */
ibmcam->curframe = framenum;
-#if 0
- /* This provides a "clean" frame but slows things down */
- memset(frame->data, 0, MAX_FRAME_SIZE);
-#endif
+
+ /*
+ * Normally we would want to copy previous frame into the current one
+ * before we even start filling it with data; this allows us to stop
+ * filling at any moment; top portion of the frame will be new and
+ * bottom portion will stay as it was in previous frame. If we don't
+ * do that then missing chunks of video stream will result in flickering
+ * portions of old data whatever it was before.
+ *
+ * If we choose not to copy previous frame (to, for example, save few
+ * bus cycles - the frame can be pretty large!) then we have an option
+ * to clear the frame before using. If we experience losses in this
+ * mode then missing picture will be black (no flickering).
+ *
+ * Finally, if user chooses not to clean the current frame before
+ * filling it with data then the old data will be visible if we fail
+ * to refill entire frame with new data.
+ */
+ if (!(flags & FLAGS_SEPARATE_FRAMES)) {
+ /* This copies previous frame into this one to mask losses */
+ memmove(frame->data, ibmcam->frame[1-framenum].data, MAX_FRAME_SIZE);
+ } else {
+ if (flags & FLAGS_CLEAN_FRAMES) {
+ /* This provides a "clean" frame but slows things down */
+ memset(frame->data, 0, MAX_FRAME_SIZE);
+ }
+ }
switch (videosize) {
case VIDEOSIZE_128x96:
frame->frmwidth = 128;
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index c30f2eaff..50970155b 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -38,10 +38,9 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
/* --------------------------------------------------------------------- */
static LIST_HEAD(superlist);
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index e370927b3..73f39db7c 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -35,20 +35,25 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-#ifndef MODULE
EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler);
+EXPORT_SYMBOL(input_register_minor);
+EXPORT_SYMBOL(input_unregister_minor);
EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_event);
-#endif
+
+#define INPUT_MAJOR 13
+#define INPUT_DEVICES 256
static struct input_dev *input_dev = NULL;
static struct input_handler *input_handler = NULL;
-
+static struct input_handler *input_table[8] = { NULL, /* ... */ };
+static devfs_handle_t input_devfs_handle = NULL;
static int input_number = 0;
+static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ };
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -142,7 +147,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
*/
while (handle) {
- handle->handler->event(handle, type, code, value);
+ if (handle->open)
+ handle->handler->event(handle, type, code, value);
handle = handle->dnext;
}
}
@@ -154,9 +160,48 @@ static void input_repeat_key(unsigned long data)
mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
}
+int input_open_device(struct input_handle *handle)
+{
+ handle->open++;
+ if (handle->dev->open)
+ return handle->dev->open(handle->dev);
+ return 0;
+}
+
+void input_close_device(struct input_handle *handle)
+{
+ if (handle->dev->close)
+ handle->dev->close(handle->dev);
+ handle->open--;
+}
+
+static void input_link_handle(struct input_handle *handle)
+{
+ handle->dnext = handle->dev->handle;
+ handle->hnext = handle->handler->handle;
+ handle->dev->handle = handle;
+ handle->handler->handle = handle;
+}
+
+static void input_unlink_handle(struct input_handle *handle)
+{
+ struct input_handle **handleptr;
+
+ handleptr = &handle->dev->handle;
+ while (*handleptr && (*handleptr != handle))
+ handleptr = &((*handleptr)->dnext);
+ *handleptr = (*handleptr)->dnext;
+
+ handleptr = &handle->handler->handle;
+ while (*handleptr && (*handleptr != handle))
+ handleptr = &((*handleptr)->hnext);
+ *handleptr = (*handleptr)->hnext;
+}
+
void input_register_device(struct input_dev *dev)
{
struct input_handler *handler = input_handler;
+ struct input_handle *handle;
/*
* Initialize repeat timer to default values.
@@ -172,17 +217,25 @@ void input_register_device(struct input_dev *dev)
* Add the device.
*/
- MOD_INC_USE_COUNT;
- dev->number = input_number++;
+ if (input_number >= INPUT_DEVICES) {
+ printk(KERN_WARNING "input: ran out of input device numbers!\n");
+ dev->number = input_number;
+ } else {
+ dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
+ set_bit(dev->number, input_devices);
+ }
+
dev->next = input_dev;
input_dev = dev;
+ input_number++;
/*
* Notify handlers.
*/
while (handler) {
- handler->connect(handler, dev);
+ if ((handle = handler->connect(handler, dev)))
+ input_link_handle(handle);
handler = handler->next;
}
}
@@ -203,6 +256,7 @@ void input_unregister_device(struct input_dev *dev)
*/
while (handle) {
+ input_unlink_handle(handle);
handle->handler->disconnect(handle);
handle = handle->dnext;
}
@@ -216,12 +270,22 @@ void input_unregister_device(struct input_dev *dev)
*devptr = (*devptr)->next;
input_number--;
- MOD_DEC_USE_COUNT;
+
+ if (dev->number < INPUT_DEVICES)
+ clear_bit(dev->number, input_devices);
}
void input_register_handler(struct input_handler *handler)
{
struct input_dev *dev = input_dev;
+ struct input_handle *handle;
+
+/*
+ * Add minors if needed.
+ */
+
+ if (handler->fops != NULL)
+ input_table[handler->minor >> 5] = handler;
/*
* Add the handler.
@@ -235,7 +299,8 @@ void input_register_handler(struct input_handler *handler)
*/
while (dev) {
- handler->connect(handler, dev);
+ if ((handle = handler->connect(handler, dev)))
+ input_link_handle(handle);
dev = dev->next;
}
}
@@ -250,6 +315,7 @@ void input_unregister_handler(struct input_handler *handler)
*/
while (handle) {
+ input_unlink_handle(handle);
handler->disconnect(handle);
handle = handle->hnext;
}
@@ -263,42 +329,59 @@ void input_unregister_handler(struct input_handler *handler)
*handlerptr = (*handlerptr)->next;
+/*
+ * Remove minors.
+ */
+
+ if (handler->fops != NULL)
+ input_table[handler->minor >> 5] = NULL;
}
-void input_open_device(struct input_handle *handle)
+static int input_open_file(struct inode *inode, struct file *file)
{
- handle->dnext = handle->dev->handle;
- handle->hnext = handle->handler->handle;
- handle->dev->handle = handle;
- handle->handler->handle = handle;
+ struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
- if (handle->dev->open)
- handle->dev->open(handle->dev);
-}
+ if (!handler || !handler->fops || !handler->fops->open)
+ return -ENODEV;
-void input_close_device(struct input_handle *handle)
-{
- struct input_handle **handleptr;
+ file->f_op = handler->fops;
- if (handle->dev->close)
- handle->dev->close(handle->dev);
-/*
- * Remove from device list of handles.
- */
+ return handler->fops->open(inode, file);
+}
- handleptr = &handle->dev->handle;
+static struct file_operations input_fops = {
+ open: input_open_file,
+};
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->dnext);
- *handleptr = (*handleptr)->dnext;
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
+{
+ char devfs_name[16];
+ sprintf(devfs_name, name, minor);
+ return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
+ S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+}
-/*
- * Remove from handler list of handles.
- */
+void input_unregister_minor(devfs_handle_t handle)
+{
+ devfs_unregister(handle);
+}
- handleptr = &handle->handler->handle;
+static int __init input_init(void)
+{
+ if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
+ printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+ return -EBUSY;
+ }
+ input_devfs_handle = devfs_mk_dir(NULL, "input", 5, NULL);
+ return 0;
+}
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->hnext);
- *handleptr = (*handleptr)->hnext;
+static void __exit input_exit(void)
+{
+ devfs_unregister(input_devfs_handle);
+ if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
+ printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
}
+
+module_init(input_init);
+module_exit(input_exit);
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 9b54300e2..585740db9 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -45,15 +45,18 @@
#include <linux/poll.h>
#include <linux/init.h>
-#define JOYDEV_MAJOR 15
+#define JOYDEV_MINOR_BASE 0
+#define JOYDEV_MINORS 32
#define JOYDEV_BUFFER_SIZE 64
struct joydev {
- char name[32];
int used;
- struct input_handle handle;
+ int open;
int minor;
+ char name[32];
+ struct input_handle handle;
wait_queue_head_t wait;
+ devfs_handle_t devfs;
struct joydev *next;
struct joydev_list *list;
struct js_corr corr[ABS_MAX];
@@ -76,11 +79,10 @@ struct joydev_list {
struct joydev_list *next;
};
-static unsigned long joydev_minors = 0;
-static struct joydev *joydev_base[BITS_PER_LONG];
+static struct joydev *joydev_table[JOYDEV_MINORS];
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_SUPPORTED_DEVICE("js");
+MODULE_SUPPORTED_DEVICE("input/js");
static int joydev_correct(int value, struct js_corr *corr)
{
@@ -164,9 +166,13 @@ static int joydev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->joydev->open)
+ input_close_device(&list->joydev->handle);
if (!--list->joydev->used) {
- clear_bit(list->joydev->minor, &joydev_minors);
+ input_unregister_minor(list->joydev->devfs);
+ joydev_table[list->joydev->minor] = NULL;
kfree(list->joydev);
}
@@ -179,28 +185,30 @@ static int joydev_release(struct inode * inode, struct file * file)
static int joydev_open(struct inode *inode, struct file *file)
{
struct joydev_list *list;
- int i = MINOR(inode->i_rdev);
+ int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
-
- if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors))
+ if (i > JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct joydev_list));
- list->joydev = joydev_base[i];
- list->next = joydev_base[i]->list;
- joydev_base[i]->list = list;
+ list->joydev = joydev_table[i];
+ list->next = joydev_table[i]->list;
+ joydev_table[i]->list = list;
file->private_data = list;
list->joydev->used++;
- MOD_INC_USE_COUNT;
+ if (!list->joydev->open++)
+ input_open_device(&list->joydev->handle);
+
return 0;
}
@@ -370,30 +378,33 @@ static struct file_operations joydev_fops = {
fasync: joydev_fasync,
};
-static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct joydev *joydev;
- int i, j;
+ int i, j, minor;
if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) &&
(test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
- || test_bit(BTN_1, dev->keybit)))) return -1;
+ || test_bit(BTN_1, dev->keybit)))) return NULL;
- if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
- return -1;
+ for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+ if (joydev_table[minor]) {
+ printk(KERN_ERR "joydev: no more free joydev devices\n");
+ return NULL;
+ }
+ if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
+ return NULL;
memset(joydev, 0, sizeof(struct joydev));
init_waitqueue_head(&joydev->wait);
- if (joydev_minors == -1) {
- printk("Can't register new joystick - 32 devices already taken.\n");
- return -1;
- }
-
sprintf(joydev->name, "joydev%d", joydev->minor);
+ joydev->minor = minor;
+ joydev_table[minor] = joydev;
+
joydev->handle.dev = dev;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
@@ -421,10 +432,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
joydev->nkey++;
}
- joydev->minor = ffz(joydev_minors);
- set_bit(joydev->minor, &joydev_minors);
- joydev_base[joydev->minor] = joydev;
-
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
if (dev->absmax[j] == dev->absmin[j]) {
@@ -439,21 +446,23 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
}
- input_open_device(&joydev->handle);
+ joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
- printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor);
+ printk("js%d: Joystick device for input%d\n", minor, dev->number);
- return 0;
+ return &joydev->handle;
}
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- input_close_device(handle);
+ if (joydev->open)
+ input_close_device(handle);
if (!--joydev->used) {
- clear_bit(joydev->minor, &joydev_minors);
+ input_unregister_minor(joydev->devfs);
+ joydev_table[joydev->minor] = NULL;
kfree(joydev);
}
}
@@ -462,14 +471,12 @@ static struct input_handler joydev_handler = {
event: joydev_event,
connect: joydev_connect,
disconnect: joydev_disconnect,
+ fops: &joydev_fops,
+ minor: JOYDEV_MINOR_BASE,
};
static int __init joydev_init(void)
{
- if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) {
- printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR);
- return -EBUSY;
- }
input_register_handler(&joydev_handler);
return 0;
}
@@ -477,8 +484,6 @@ static int __init joydev_init(void)
static void __exit joydev_exit(void)
{
input_unregister_handler(&joydev_handler);
- if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: can't unregister device\n");
}
module_init(joydev_init);
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 7c94c185b..4723ba11b 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -36,17 +36,63 @@
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
+
+static int x86_sysrq_alt = 0;
+
+static unsigned short x86_keycodes[256] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 89, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+ 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+ 367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
+ 360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
+ 103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
+ 291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+ 118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
+ 271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
+ 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
+ 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
+
+static int emulate_raw(unsigned int keycode, int down)
+{
+ if (keycode > 255 || !x86_keycodes[keycode])
+ return -1;
+
+ if (keycode == KEY_PAUSE) {
+ handle_scancode(0xe1, 1);
+ handle_scancode(0x1d, down);
+ handle_scancode(0x45, down);
+ return 0;
+ }
+
+ if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
+ handle_scancode(0x54, down);
+ return 0;
+ }
+
+ if (x86_keycodes[keycode] & 0x100)
+ handle_scancode(0xe0, 1);
-static unsigned char keybdev_x86_e0s[] =
- { 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
- 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52, 0x53,
- 0x26, 0x25, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00,
- 0x23, 0x24, 0x25, 0x26, 0x27 };
+ handle_scancode(x86_keycodes[keycode] & 0x7f, down);
-#elif CONFIG_ADB_KEYBOARD
+ if (keycode == KEY_SYSRQ) {
+ handle_scancode(0xe0, 1);
+ handle_scancode(0x37, down);
+ }
+
+ if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
+ x86_sysrq_alt = down;
-static unsigned char keybdev_mac_codes[256] =
+ return 0;
+}
+
+#elif defined(CONFIG_ADB_KEYBOARD)
+
+static unsigned char mac_keycodes[128] =
{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
@@ -56,10 +102,19 @@ static unsigned char keybdev_mac_codes[256] =
76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
+static int emulate_raw(unsigned int code, unsigned char upflag)
+{
+ if (keycode > 127 || !mac_keycodes[keycode])
+ return -1;
+
+ handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+ return 0;
+}
+
#endif
static struct input_handler keybdev_handler;
-static int keybdev_alt = 0;
void keybdev_ledfunc(unsigned int led)
{
@@ -76,70 +131,30 @@ void keybdev_ledfunc(unsigned int led)
void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
{
- if (type != EV_KEY || code > 255) return;
+ if (type != EV_KEY) return;
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
-
- if (code >= 189) {
- printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
- return;
- } else if (code >= 162) {
- handle_scancode(0xe0, 1);
- handle_scancode(code - 161, down);
- } else if (code >= 125) {
- handle_scancode(0xe0, 1);
- handle_scancode(code - 34, down);
- } else if (code == 119) {
- handle_scancode(0xe1, 1);
- handle_scancode(0x1d, down);
- handle_scancode(0x45, down);
- } else if (code >= 96) {
- if (code == 99 && keybdev_alt) {
- handle_scancode(84, down);
- } else {
- handle_scancode(0xe0, 1);
- handle_scancode(keybdev_x86_e0s[code - 96], down);
- if (code == 99) {
- handle_scancode(0xe0, 1);
- handle_scancode(0x37, down);
- }
- }
- } else if (code == 84) {
- handle_scancode(43, down);
- } else handle_scancode(code, down);
-
- if (code == 56 || code == 100) keybdev_alt = down;
-
-#elif CONFIG_ADB_KEYBOARD
-
- if (code < 128 && keybdev_mac_codes[code])
- handle_scancode(keybdev_mac_codes[code] & 0x7f, down);
- else
- printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
-
-#else
-#error "Cannot generate rawmode keyboard for your architecture yet."
-#endif
+ if (emulate_raw(code, down))
+ printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
tasklet_schedule(&keyboard_tasklet);
}
-static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct input_handle *handle;
int i;
if (!test_bit(EV_KEY, dev->evbit))
- return -1;
+ return NULL;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
if (test_bit(i, dev->keybit)) break;
if (i == BTN_MISC)
- return -1;
+ return NULL;
if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return -1;
+ return NULL;
memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev;
@@ -149,15 +164,13 @@ static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
printk("keybdev.c: Adding keyboard: input%d\n", dev->number);
- return 0;
+ return handle;
}
static void keybdev_disconnect(struct input_handle *handle)
{
printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
-
input_close_device(handle);
-
kfree(handle);
}
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
index c8063c927..a45f8c798 100644
--- a/drivers/usb/mdc800.c
+++ b/drivers/usb/mdc800.c
@@ -26,11 +26,19 @@
* To use the Camera you must support the USB Protocoll of the camera
* to the Kernel Node.
* The Driver uses a misc device Node. Create it with :
- * mknod /dev/mustek c 10 171
+ * mknod /dev/mustek c 180 32
*
* The driver supports only one camera.
*
* version 0.7.1
+ * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
+ * problems when compiled as Module.
+ * (04/04/2000)
+ *
+ * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
+ * was updated to use these values.
+ * (26/03/2000)
+ *
* The Init und Exit Module Function are updated.
* (01/03/2000)
*
@@ -57,7 +65,6 @@
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
-#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
@@ -67,22 +74,22 @@
#include <linux/usb.h>
#define VERSION "0.7.1"
-#define RELEASE_DATE "(01/03/2000)"
+#define RELEASE_DATE "(26/03/2000)"
/* Vendor and Product Information */
#define MDC800_VENDOR_ID 0x055f
#define MDC800_PRODUCT_ID 0xa800
/* Timeouts (msec) */
-#define TO_READ_FROM_IRQ 4000
+#define TO_READ_FROM_IRQ 4000
#define TO_GET_READY 2000
-#define TO_DOWNLOAD_GET_READY 1500
-#define TO_DOWNLOAD_GET_BUSY 1500
-#define TO_WRITE_GET_READY 3000
-#define TO_DEFAULT_COMMAND 5000
+#define TO_DOWNLOAD_GET_READY 1500
+#define TO_DOWNLOAD_GET_BUSY 1500
+#define TO_WRITE_GET_READY 3000
+#define TO_DEFAULT_COMMAND 5000
-/* Minor Number of the device (create with mknod /dev/mustek c 10 171) */
-#define MDC800_DEVICE_MINOR 171
+/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
+#define MDC800_DEVICE_MINOR_BASE 32
/**************************************************************************
@@ -514,11 +521,20 @@ static int mdc800_getAnswerSize (char command)
static int mdc800_device_open (struct inode* inode, struct file *file)
{
int retval=0;
+
+ MOD_INC_USE_COUNT;
+
if (mdc800->state == NOT_CONNECTED)
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
if (mdc800->open)
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
mdc800->rw_lock=0;
mdc800->in_count=0;
@@ -535,10 +551,10 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
if (usb_submit_urb (mdc800->irq_urb))
{
err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- MOD_INC_USE_COUNT;
mdc800->open=1;
dbg ("Mustek MDC800 device opened.");
@@ -792,21 +808,6 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
Init and Cleanup this driver (Structs and types)
****************************************************************************/
-
-/*
- * USB Driver Struct for this device
- */
-static struct usb_driver mdc800_usb_driver =
-{
- "mdc800",
- mdc800_usb_probe,
- mdc800_usb_disconnect,
- { 0,0 },
- 0,
- 0
-};
-
-
/* File Operations of this drivers */
static struct file_operations mdc800_device_ops =
{
@@ -828,17 +829,22 @@ static struct file_operations mdc800_device_ops =
};
+
/*
- * The Misc Device Configuration Struct
+ * USB Driver Struct for this device
*/
-static struct miscdevice mdc800_device =
+static struct usb_driver mdc800_usb_driver =
{
- MDC800_DEVICE_MINOR,
- "USB Mustek MDC800 Camera",
- &mdc800_device_ops
+ "mdc800",
+ mdc800_usb_probe,
+ mdc800_usb_disconnect,
+ { 0,0 },
+ &mdc800_device_ops,
+ MDC800_DEVICE_MINOR_BASE
};
+
/************************************************************************
Init and Cleanup this driver (Main Functions)
*************************************************************************/
@@ -872,8 +878,6 @@ int __init usb_mdc800_init (void)
/* Register the driver */
if (usb_register (&mdc800_usb_driver) < 0)
goto cleanup_on_fail;
- if (misc_register (&mdc800_device) < 0)
- goto cleanup_on_misc_register_fail;
info ("Mustek Digital Camera Driver " VERSION " (MDC800)");
info (RELEASE_DATE " Henning Zabel <henning@uni-paderborn.de>");
@@ -882,9 +886,6 @@ int __init usb_mdc800_init (void)
/* Clean driver up, when something fails */
-cleanup_on_misc_register_fail:
- usb_deregister (&mdc800_usb_driver);
-
cleanup_on_fail:
if (mdc800 != 0)
@@ -909,7 +910,6 @@ cleanup_on_fail:
void __exit usb_mdc800_cleanup (void)
{
usb_deregister (&mdc800_usb_driver);
- misc_deregister (&mdc800_device);
usb_free_urb (mdc800->irq_urb);
usb_free_urb (mdc800->download_urb);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index bfdc4ab3d..765f61556 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -29,8 +29,9 @@
*/
#define MOUSEDEV_MINOR_BASE 32
+#define MOUSEDEV_MINORS 32
+#define MOUSEDEV_MIX 31
-#include <linux/miscdevice.h>
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/module.h>
@@ -46,12 +47,13 @@
#endif
struct mousedev {
- char name[32];
int used;
- struct input_handle handle;
- struct miscdevice misc;
+ int open;
+ int minor;
wait_queue_head_t wait;
struct mousedev_list *list;
+ struct input_handle handle;
+ devfs_handle_t devfs;
};
struct mousedev_list {
@@ -71,77 +73,80 @@ struct mousedev_list {
static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-static struct mousedev mousedev_single;
-#else
-static unsigned long mousedev_miscbits = 0;
-static struct mousedev *mousedev_base[BITS_PER_LONG];
-#endif
+static struct input_handler mousedev_handler;
+
+static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static struct mousedev mousedev_mix;
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
- struct mousedev *mousedev = handle->private;
- struct mousedev_list *list = mousedev->list;
+ struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
+ struct mousedev **mousedev = mousedevs;
+ struct mousedev_list *list;
int index, size;
- while (list) {
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
- list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
- list->oldx += list->dx * size;
- break;
- case ABS_Y:
- size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
- list->oldy -= list->dy * size;
- break;
- }
- break;
- case EV_REL:
- switch (code) {
- case REL_X: list->dx += value; break;
- case REL_Y: list->dy -= value; break;
- case REL_WHEEL: if (list->mode) list->dz -= value; break;
- }
- break;
+ while (*mousedev) {
+ list = (*mousedev)->list;
+ while (list) {
+ switch (type) {
+ case EV_ABS:
+ switch (code) {
+ case ABS_X:
+ size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
+ list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
+ list->oldx += list->dx * size;
+ break;
+ case ABS_Y:
+ size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
+ list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+ list->oldy -= list->dy * size;
+ break;
+ }
+ break;
+ case EV_REL:
+ switch (code) {
+ case REL_X: list->dx += value; break;
+ case REL_Y: list->dy -= value; break;
+ case REL_WHEEL: if (list->mode) list->dz -= value; break;
+ }
+ break;
+
+ case EV_KEY:
+ switch (code) {
+ case BTN_0:
+ case BTN_TOUCH:
+ case BTN_LEFT: index = 0; break;
+ case BTN_4:
+ case BTN_EXTRA: if (list->mode > 1) { index = 4; break; }
+ case BTN_STYLUS:
+ case BTN_1:
+ case BTN_RIGHT: index = 1; break;
+ case BTN_3:
+ case BTN_SIDE: if (list->mode > 1) { index = 3; break; }
+ case BTN_2:
+ case BTN_STYLUS2:
+ case BTN_MIDDLE: index = 2; break;
+ default: return;
+ }
+ switch (value) {
+ case 0: clear_bit(index, &list->buttons); break;
+ case 1: set_bit(index, &list->buttons); break;
+ case 2: return;
+ }
+ break;
+ }
+
+ list->ready = 1;
- case EV_KEY:
- switch (code) {
- case BTN_0:
- case BTN_TOUCH:
- case BTN_LEFT: index = 0; break;
- case BTN_4:
- case BTN_EXTRA: if (list->mode > 1) { index = 4; break; }
- case BTN_STYLUS:
- case BTN_1:
- case BTN_RIGHT: index = 1; break;
- case BTN_3:
- case BTN_SIDE: if (list->mode > 1) { index = 3; break; }
- case BTN_2:
- case BTN_STYLUS2:
- case BTN_MIDDLE: index = 2; break;
- default: return;
- }
- switch (value) {
- case 0: clear_bit(index, &list->buttons); break;
- case 1: set_bit(index, &list->buttons); break;
- case 2: return;
- }
- break;
- }
-
- list->ready = 1;
+ if (list->fasync)
+ kill_fasync(list->fasync, SIGIO, POLL_IN);
- if (list->fasync)
- kill_fasync(list->fasync, SIGIO, POLL_IN);
+ list = list->next;
+ }
- list = list->next;
+ wake_up_interruptible(&((*mousedev)->wait));
+ mousedev++;
}
-
- wake_up_interruptible(&mousedev->wait);
}
static int mousedev_fasync(int fd, struct file *file, int on)
@@ -162,14 +167,27 @@ static int mousedev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->mousedev->open) {
+ if (list->mousedev->minor == MOUSEDEV_MIX) {
+ struct input_handle *handle = mousedev_handler.handle;
+ while (handle) {
+ struct mousedev *mousedev = handle->private;
+ if (!mousedev->open)
+ input_close_device(handle);
+ handle = handle->hnext;
+ }
+ } else {
+ if (!mousedev_mix.open)
+ input_close_device(&list->mousedev->handle);
+ }
+ }
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
if (!--list->mousedev->used) {
- clear_bit(list->mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
- misc_deregister(&list->mousedev->misc);
+ input_unregister_minor(list->mousedev->devfs);
+ mousedev_table[list->mousedev->minor] = NULL;
kfree(list->mousedev);
}
-#endif
kfree(list);
@@ -180,33 +198,41 @@ static int mousedev_release(struct inode * inode, struct file * file)
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
-
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
- if (i > BITS_PER_LONG || !test_bit(i, &mousedev_miscbits))
+
+ if (i > MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
-#endif
- if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct mousedev_list));
+ list->mousedev = mousedev_table[i];
+ list->next = mousedev_table[i]->list;
+ mousedev_table[i]->list = list;
+ file->private_data = list;
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- list->mousedev = &mousedev_single;
- list->next = mousedev_single.list;
- mousedev_single.list = list;
-#else
- list->mousedev = mousedev_base[i];
- list->next = mousedev_base[i]->list;
- mousedev_base[i]->list = list;
list->mousedev->used++;
-#endif
- file->private_data = list;
+ if (!list->mousedev->open++) {
+ if (list->mousedev->minor == MOUSEDEV_MIX) {
+ struct input_handle *handle = mousedev_handler.handle;
+ while (handle) {
+ struct mousedev *mousedev = handle->private;
+ if (!mousedev->open)
+ input_open_device(handle);
+ handle = handle->hnext;
+ }
+ } else {
+ if (!mousedev_mix.open)
+ input_open_device(&list->mousedev->handle);
+ }
+ }
- MOD_INC_USE_COUNT;
return 0;
}
@@ -357,119 +383,93 @@ struct file_operations mousedev_fops = {
fasync: mousedev_fasync,
};
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
{
+ struct mousedev *mousedev;
+ int minor = 0;
if (!test_bit(EV_KEY, dev->evbit) ||
(!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
- return -1;
+ return NULL;
if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
(!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
- return -1;
-
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- {
- struct input_handle *handle;
-
- if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return -1;
-
- memset(handle, 0, sizeof(struct input_handle));
+ return NULL;
- handle->dev = dev;
- handle->handler = handler;
- handle->private = &mousedev_single;
-
- input_open_device(handle);
-
- printk("mousedev.c: Adding mouse: input%d\n", dev->number);
+ for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+ if (mousedev_table[minor]) {
+ printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+ return NULL;
}
-#else
- {
- struct mousedev *mousedev;
-
- if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
- return -1;
- memset(mousedev, 0, sizeof(struct mousedev));
+ if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
+ return NULL;
+ memset(mousedev, 0, sizeof(struct mousedev));
+ init_waitqueue_head(&mousedev->wait);
- mousedev->misc.minor = ffz(mousedev_miscbits);
- set_bit(mousedev->misc.minor, &mousedev_miscbits);
- mousedev_base[mousedev->misc.minor] = mousedev;
+ mousedev->used = 1;
+ mousedev->minor = minor;
+ mousedev_table[minor] = mousedev;
- sprintf(mousedev->name, "mousedev%d", mousedev->misc.minor);
- mousedev->misc.name = mousedev->name;
- mousedev->misc.minor += MOUSEDEV_MINOR_BASE;
- mousedev->misc.fops = &mousedev_fops;
+ mousedev->handle.dev = dev;
+ mousedev->handle.handler = handler;
+ mousedev->handle.private = mousedev;
- mousedev->handle.dev = dev;
- mousedev->handle.handler = handler;
- mousedev->handle.private = mousedev;
+ mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
- init_waitqueue_head(&mousedev->wait);
-
- mousedev->used = 1;
-
- misc_register(&mousedev->misc);
+ if (mousedev_mix.open) {
input_open_device(&mousedev->handle);
-
- printk("%s: PS/2 mouse device for input%d on misc%d\n",
- mousedev->name, dev->number, mousedev->misc.minor);
+ mousedev_mix.open++;
}
-#endif
- return 0;
+ printk("mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
+
+ return &mousedev->handle;
}
static void mousedev_disconnect(struct input_handle *handle)
{
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- printk("mousedev.c: Removing mouse: input%d\n", handle->dev->number);
- input_close_device(handle);
- kfree(handle);
-#else
struct mousedev *mousedev = handle->private;
- input_close_device(handle);
+
+ if (mousedev->open || mousedev_mix.open) {
+ input_close_device(handle);
+ mousedev_mix.open--;
+ }
+
if (!--mousedev->used) {
- clear_bit(mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
- misc_deregister(&mousedev->misc);
+ input_unregister_minor(mousedev->devfs);
+ mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
}
-#endif
}
static struct input_handler mousedev_handler = {
event: mousedev_event,
connect: mousedev_connect,
disconnect: mousedev_disconnect,
+ fops: &mousedev_fops,
+ minor: MOUSEDEV_MINOR_BASE,
};
static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- memset(&mousedev_single, 0, sizeof(struct mousedev));
-
- init_waitqueue_head(&mousedev_single.wait);
- mousedev_single.misc.minor = MOUSEDEV_MINOR_BASE;
- mousedev_single.misc.name = "mousedev";
- mousedev_single.misc.fops = &mousedev_fops;
+ memset(&mousedev_mix, 0, sizeof(struct mousedev));
+ init_waitqueue_head(&mousedev_mix.wait);
+ mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
+ mousedev_mix.used = 1;
+ mousedev_mix.minor = MOUSEDEV_MIX;
+ mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
- misc_register(&mousedev_single.misc);
-
- printk("mousedev: PS/2 mouse device on misc%d\n", mousedev_single.misc.minor);
-#endif
+ printk("mice: PS/2 mouse device common for all mice\n");
return 0;
}
static void __exit mousedev_exit(void)
{
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- misc_deregister(&mousedev_single.misc);
-#endif
+ input_unregister_minor(mousedev_mix.devfs);
input_unregister_handler(&mousedev_handler);
}
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index d1f5048e3..78551b77c 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -4,12 +4,13 @@
* Many improvements by Bret Wallach
* Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
* Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
*
* Based on the Linux CPiA driver.
*
* Released under GPL v.2 license.
*
- * Version: 1.09
+ * Version: 1.11
*
* Please see the file: linux/Documentation/usb/ov511.txt
* and the website at: http://alpha.dyndns.org/ov511
@@ -34,8 +35,6 @@
#define __NO_VERSION__
-/* Handle mangled (versioned) external symbols */
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
@@ -83,10 +82,14 @@ static int fix_rgb_offset = 0;
/* Snapshot mode enabled flag */
static int snapshot = 0;
+/* Sensor detection override (global for all attached cameras) */
+static int sensor = 0;
+
MODULE_PARM(autoadjust, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(fix_rgb_offset, "i");
MODULE_PARM(snapshot, "i");
+MODULE_PARM(sensor, "i");
MODULE_AUTHOR("Mark McClelland (and others)");
MODULE_DESCRIPTION("OV511 USB Camera Driver");
@@ -210,7 +213,9 @@ static void rvfree(void *mem, unsigned long size)
vfree(mem);
}
-int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_reg_write(struct usb_device *dev,
+ unsigned char reg,
+ unsigned char value)
{
int rc;
@@ -219,14 +224,17 @@ int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char val
2 /* REG_IO */,
USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, &value, 1, HZ);
-
+
PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc);
-
+
+ if (rc < 0)
+ err("ov511_reg_write: error %d", rc);
+
return rc;
}
/* returns: negative is error, pos or zero is data */
-int ov511_reg_read(struct usb_device *dev, unsigned char reg)
+static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
{
int rc;
unsigned char buffer[1];
@@ -239,13 +247,17 @@ int ov511_reg_read(struct usb_device *dev, unsigned char reg)
PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
- if(rc < 0)
+ if(rc < 0) {
+ err("ov511_reg_read: error %d", rc);
return rc;
+ }
else
return buffer[0];
}
-int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_i2c_write(struct usb_device *dev,
+ unsigned char reg,
+ unsigned char value)
{
int rc, retries;
@@ -255,19 +267,19 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Write "value" to I2C data port of OV511 */
rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Initiate 3-byte write cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
@@ -275,14 +287,22 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
/* I2C abort */
ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
#endif
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c write retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
return 0;
+
+error:
+ err("ov511_i2c_write: error %d", rc);
+ return rc;
}
/* returns: negative is error, pos or zero is data */
-int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
+static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
{
int rc, value, retries;
@@ -290,15 +310,15 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Initiate 2-byte write cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
@@ -306,27 +326,35 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
/* I2C abort */
ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c write retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
/* Two byte read cycle */
for(retries = OV511_I2C_RETRIES;;) {
/* Initiate 2-byte read cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
/* I2C abort */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c read retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
@@ -335,60 +363,41 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
/* This is needed to make ov511_i2c_write() work */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
- return (value);
-}
-
-
-// This version doesn't always work
-#if 0
- /* returns: negative is error, pos or zero is data */
- int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
- {
- int rc, value;
-
- /* Select camera register */
- rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
- if (rc < 0) return rc;
-
-
- /* Initiate 2-byte write cycle */
- rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
- if (rc < 0) return rc;
-
-
- /* Initiate 2-byte read cycle */
- rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
-
- value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+ return value;
- PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value);
-
- return (value);
- }
-#endif
+error:
+ err("ov511_i2c_read: error %d", rc);
+ return rc;
+}
static int ov511_write_regvals(struct usb_device *dev,
struct ov511_regvals * pRegvals)
{
- int ret;
+ int rc;
+
while(pRegvals->bus != OV511_DONE_BUS) {
if (pRegvals->bus == OV511_REG_BUS) {
- if ((ret = ov511_reg_write(dev, pRegvals->reg,
+ if ((rc = ov511_reg_write(dev, pRegvals->reg,
pRegvals->val)) < 0)
- return ret;
+ goto error;
} else if (pRegvals->bus == OV511_I2C_BUS) {
- if ((ret = ov511_i2c_write(dev, pRegvals->reg,
+ if ((rc = ov511_i2c_write(dev, pRegvals->reg,
pRegvals->val)) < 0)
- return ret;
+ goto error;
} else {
- err("Bad regval array");
+ err("Bad regval array");
+ rc = -1;
+ goto error;
}
pRegvals++;
}
return 0;
+
+error:
+ err("ov511_write_regvals: error %d", rc);
+ return rc;
}
#if 0
@@ -396,10 +405,9 @@ static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
- for(i=reg1; i<=regn; i++) {
- rc = ov511_i2c_read(dev, i);
-
- PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
+ for(i = reg1; i <= regn; i++) {
+ rc = ov511_i2c_read(dev, i);
+ PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
}
}
@@ -413,7 +421,7 @@ static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
- for(i=reg1; i<=regn; i++) {
+ for(i = reg1; i <= regn; i++) {
rc = ov511_reg_read(dev, i);
PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc);
}
@@ -443,72 +451,82 @@ static void ov511_dump_regs( struct usb_device *dev)
}
#endif
-int ov511_reset(struct usb_device *dev, unsigned char reset_type)
+static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
PDEBUG(3, "Reset: type=0x%X", reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
- if (rc < 0)
- err("reset: command failed");
-
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+
if (rc < 0)
err("reset: command failed");
return rc;
}
-int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov511_stop(struct usb_device *dev)
{
- int alt, multiplier, rc;
-
- PDEBUG(3, "set packet size: %d", size);
-
- switch (size) {
- case 992:
- alt = 0;
- multiplier = 31;
- break;
- case 993:
- alt = 1;
- multiplier = 31;
- break;
- case 768:
- alt = 2;
- multiplier = 24;
- break;
- case 769:
- alt = 3;
- multiplier = 24;
- break;
- case 512:
- alt = 4;
- multiplier = 16;
- break;
- case 513:
- alt = 5;
- multiplier = 16;
- break;
- case 257:
- alt = 6;
- multiplier = 8;
- break;
- case 0:
- alt = 7;
- multiplier = 1; // FIXME - is this correct?
- break;
- default:
+ PDEBUG(4, "ov511_stop()");
+ return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called */
+static inline int ov511_restart(struct usb_device *dev)
+{
+ PDEBUG(4, "ov511_restart()");
+ return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
+}
+
+static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+{
+ int alt, mult;
+
+ if (ov511_stop(ov511->dev) < 0)
+ return -EIO;
+
+ mult = size / 32;
+
+ if (ov511->bridge == BRG_OV511) {
+ if (size == 0) alt = OV511_ALT_SIZE_0;
+ else if (size == 257) alt = OV511_ALT_SIZE_257;
+// else if (size == 512) alt = OV511_ALT_SIZE_512;
+ else if (size == 513) alt = OV511_ALT_SIZE_513;
+// else if (size == 768) alt = OV511_ALT_SIZE_768;
+ else if (size == 769) alt = OV511_ALT_SIZE_769;
+// else if (size == 992) alt = OV511_ALT_SIZE_992;
+ else if (size == 993) alt = OV511_ALT_SIZE_993;
+ else {
err("Set packet size: invalid size (%d)", size);
return -EINVAL;
+ }
+ }
+ else if (ov511->bridge == BRG_OV511PLUS) {
+ if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
+ else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
+ else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
+ else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;
+ else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;
+ else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;
+ else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;
+ else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;
+ else {
+ err("Set packet size: invalid size (%d)", size);
+ return -EINVAL;
+ }
+ }
+ else {
+ err("Set packet size: Invalid bridge type");
+ return -EINVAL;
}
- rc = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
- multiplier);
- if (rc < 0) {
- err("Set packet size: Set FIFO size ret %d", rc);
+ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+
+ if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+ mult) < 0)
return -ENOMEM;
- }
if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
err("Set packet size: set interface error");
@@ -519,6 +537,11 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
return -ENOMEM;
+ ov511->packet_size = size;
+
+ if (ov511_restart(ov511->dev) < 0)
+ return -EIO;
+
return 0;
}
@@ -526,34 +549,44 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
struct video_picture *p)
{
int ret;
+ struct usb_device *dev = ov511->dev;
- /* Stop the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ PDEBUG(4, "ov511_set_picture");
+
+ if (ov511_stop(dev) < 0)
return -EIO;
- }
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_COM_B)) < 0)
+ if((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
return -EIO;
#if 0
- if(ov511_i2c_write(ov511->dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+ if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
return -EIO;
#endif
+ if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE)
+ if(ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+ return -EIO;
+
+ if (ov511->sensor == SEN_OV7610) {
+ if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+ return -EIO;
+ }
+ else if ((ov511->sensor == SEN_OV7620)
+ || (ov511->sensor == SEN_OV7620AE)) {
+// cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+// cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+// // DEBUG_CODE
+// PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+// ov511_i2c_read(dev, OV7610_REG_BRT));
+//
+// if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+// return -EIO;
+ }
- if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0)
- return -EIO;
-
- if(ov511_i2c_write(ov511->dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
- return -EIO;
-
- if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
- return -EIO;
-
- /* Restart the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
- err("reset: command failed");
+ if (ov511_restart(dev) < 0)
return -EIO;
- }
return 0;
}
@@ -562,20 +595,20 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
struct video_picture *p)
{
int ret;
+ struct usb_device *dev = ov511->dev;
- /* Stop the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ PDEBUG(4, "ov511_get_picture");
+
+ if (ov511_stop(dev) < 0)
return -EIO;
- }
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO;
p->colour = ret << 8;
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_CNT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO;
p->contrast = ret << 8;
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_BRT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO;
p->brightness = ret << 8;
p->hue = 0x8000;
@@ -583,11 +616,8 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
p->depth = 3; /* Don't know if this is right */
p->palette = VIDEO_PALETTE_RGB24;
- /* Restart the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
- err("reset: command failed");
+ if (ov511_restart(dev) < 0)
return -EIO;
- }
return 0;
}
@@ -597,67 +627,93 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
{
int rc = 0;
struct usb_device *dev = ov511->dev;
+ int hwsbase = 0;
+ int hwebase = 0;
PDEBUG(3, "ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)",
width, height, mode, sub_flag);
-// ov511_set_packet_size(ov511, 0);
- if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ if (ov511_stop(ov511->dev) < 0)
return -EIO;
- }
if (mode == VIDEO_PALETTE_GREY) {
ov511_reg_write(dev, 0x16, 0x00);
- ov511_i2c_write(dev, 0x0e, 0x44);
- ov511_i2c_write(dev, 0x13, 0x21);
+ if (ov511->sensor == SEN_OV7610
+ || ov511->sensor == SEN_OV7620AE) {
+ /* these aren't valid on the OV7620 */
+ ov511_i2c_write(dev, 0x0e, 0x44);
+ }
+ ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
/* For snapshot */
ov511_reg_write(dev, 0x1e, 0x00);
ov511_reg_write(dev, 0x1f, 0x01);
} else {
ov511_reg_write(dev, 0x16, 0x01);
- ov511_i2c_write(dev, 0x0e, 0x04);
- ov511_i2c_write(dev, 0x13, 0x01);
+ if (ov511->sensor == SEN_OV7610
+ || ov511->sensor == SEN_OV7620AE) {
+ /* not valid on the OV7620 */
+ ov511_i2c_write(dev, 0x0e, 0x04);
+ }
+ ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
/* For snapshot */
ov511_reg_write(dev, 0x1e, 0x01);
ov511_reg_write(dev, 0x1f, 0x03);
}
+ /* The different sensor ICs handle setting up of window differently */
+ switch (ov511->sensor) {
+ case SEN_OV7610:
+ case SEN_OV7620AE:
+ hwsbase = 0x38;
+ hwebase = 0x3a; break;
+ case SEN_OV7620:
+ hwsbase = 0x2c;
+ hwebase = 0x2d; break;
+ default:
+ hwsbase = 0;
+ hwebase = 0; break;
+ }
+
if (width == 640 && height == 480) {
if (sub_flag) {
- ov511_i2c_write(ov511->dev, 0x17, 0x38+(ov511->subx>>2));
- ov511_i2c_write(ov511->dev, 0x18,
- 0x3a+((ov511->subx+ov511->subw)>>2));
- ov511_i2c_write(ov511->dev, 0x19, 0x5+(ov511->suby>>1));
- ov511_i2c_write(ov511->dev, 0x1a,
+ /* horizontal window start */
+ ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
+ /* horizontal window end */
+ ov511_i2c_write(dev, 0x18,
+ hwebase+((ov511->subx+ov511->subw)>>2));
+ /* vertical window start */
+ ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+ /* vertical window end */
+ ov511_i2c_write(dev, 0x1a,
0x5+((ov511->suby+ov511->subh)>>1));
- ov511_reg_write(ov511->dev, 0x12, (ov511->subw>>3)-1);
- ov511_reg_write(ov511->dev, 0x13, (ov511->subh>>3)-1);
+ ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
+ ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
+ /* clock rate control */
ov511_i2c_write(dev, 0x11, 0x01);
/* Snapshot additions */
- ov511_reg_write(ov511->dev, 0x1a, (ov511->subw>>3)-1);
- ov511_reg_write(ov511->dev, 0x1b, (ov511->subh>>3)-1);
- ov511_reg_write(ov511->dev, 0x1c, 0x00);
- ov511_reg_write(ov511->dev, 0x1d, 0x00);
+ ov511_reg_write(dev, 0x1a, (ov511->subw>>3)-1);
+ ov511_reg_write(dev, 0x1b, (ov511->subh>>3)-1);
+ ov511_reg_write(dev, 0x1c, 0x00);
+ ov511_reg_write(dev, 0x1d, 0x00);
} else {
- ov511_i2c_write(ov511->dev, 0x17, 0x38);
- ov511_i2c_write(ov511->dev, 0x18, 0x3a + (640>>2));
- ov511_i2c_write(ov511->dev, 0x19, 0x5);
- ov511_i2c_write(ov511->dev, 0x1a, 5 + (480>>1));
+ ov511_i2c_write(dev, 0x17, hwsbase);
+ ov511_i2c_write(dev, 0x18, hwebase + (640>>2));
+ ov511_i2c_write(dev, 0x19, 0x5);
+ ov511_i2c_write(dev, 0x1a, 5 + (480>>1));
ov511_reg_write(dev, 0x12, 0x4f);
ov511_reg_write(dev, 0x13, 0x3d);
/* Snapshot additions */
- ov511_reg_write(ov511->dev, 0x1a, 0x4f);
- ov511_reg_write(ov511->dev, 0x1b, 0x3d);
- ov511_reg_write(ov511->dev, 0x1c, 0x00);
- ov511_reg_write(ov511->dev, 0x1d, 0x00);
+ ov511_reg_write(dev, 0x1a, 0x4f);
+ ov511_reg_write(dev, 0x1b, 0x3d);
+ ov511_reg_write(dev, 0x1c, 0x00);
+ ov511_reg_write(dev, 0x1d, 0x00);
if (mode == VIDEO_PALETTE_GREY) {
- ov511_i2c_write(dev, 0x11, 4); /* check */
+ ov511_i2c_write(dev, 0x11, 4); /* check */
} else {
- ov511_i2c_write(dev, 0x11, 6); /* check */
+ ov511_i2c_write(dev, 0x11, 6); /* check */
}
}
@@ -669,7 +725,10 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
ov511_i2c_write(dev, 0x12, 0x24);
ov511_i2c_write(dev, 0x14, 0x04);
- ov511_i2c_write(dev, 0x35, 0x9e);
+
+ /* 7620 doesn't have register 0x35, so play it safe */
+ if (ov511->sensor != SEN_OV7620)
+ ov511_i2c_write(dev, 0x35, 0x9e);
} else if (width == 320 && height == 240) {
ov511_reg_write(dev, 0x12, 0x27);
ov511_reg_write(dev, 0x13, 0x1f);
@@ -697,12 +756,8 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
rc = -EINVAL;
}
-// ov511_set_packet_size(ov511, 993);
-
- if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00) < 0) {
- err("reset: command failed");
+ if (ov511_restart(ov511->dev) < 0)
return -EIO;
- }
return rc;
}
@@ -928,29 +983,30 @@ static void ov511_parse_data_grey(unsigned char * pIn0,
*************************************************************/
static void fixFrameRGBoffset(struct ov511_frame *frame)
{
- int x,y;
- int rowBytes=frame->width*3,w=frame->width;
- unsigned char *rgb=frame->data;
- const int shift=1;//Distance to shift pixels by, vertically
+ int x, y;
+ int rowBytes = frame->width*3, w = frame->width;
+ unsigned char *rgb = frame->data;
+ const int shift = 1; //Distance to shift pixels by, vertically
- if (frame->width<400)
- return;//Don't bother with little images
+ if (frame->width < 400)
+ return; //Don't bother with little images
//Shift red channel up
- for (y=shift;y<frame->height;y++)
+ for (y = shift; y < frame->height; y++)
{
- int lp=(y-shift)*rowBytes;//Previous line offset
- int lc=y*rowBytes;//Current line offset
- for (x=0;x<w;x++)
- rgb[lp+x*3+2]=rgb[lc+x*3+2];//Shift red up
+ int lp = (y-shift)*rowBytes; //Previous line offset
+ int lc = y*rowBytes; //Current line offset
+ for (x = 0; x < w; x++)
+ rgb[lp+x*3+2] = rgb[lc+x*3+2]; //Shift red up
}
+
//Shift blue channel down
- for (y=frame->height-shift-1;y>=0;y--)
+ for (y=frame->height-shift-1; y >= 0; y--)
{
- int ln=(y+shift)*rowBytes;//Next line offset
- int lc=y*rowBytes;//Current line offset
- for (x=0;x<w;x++)
- rgb[ln+x*3+0]=rgb[lc+x*3+0];//Shift blue down
+ int ln = (y+shift)*rowBytes; //Next line offset
+ int lc = y*rowBytes; //Current line offset
+ for (x = 0; x < w; x++)
+ rgb[ln+x*3+0] = rgb[lc+x*3+0]; //Shift blue down
}
}
@@ -962,6 +1018,8 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
int aPackNum[10];
struct ov511_frame *frame;
+ PDEBUG(4, "ov511_move_data");
+
for (i = 0; i < urb->number_of_packets; i++) {
int n = urb->iso_frame_desc[i].actual_length;
int st = urb->iso_frame_desc[i].status;
@@ -969,7 +1027,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
urb->iso_frame_desc[i].status = 0;
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- aPackNum[i] = n ? cdata[992] : -1;
+ aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
if (!n || ov511->curframe == -1) continue;
@@ -988,7 +1046,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
do_gettimeofday(ts);
PDEBUG(4, "Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d",
- ov511->curframe, (int)(cdata[992]),
+ ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
(int)(cdata[9]), (int)(cdata[10]));
if (frame->scanstate == STATE_LINES) {
@@ -1051,7 +1109,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
}
/* Parse the segments */
- while(iPix <= 992 - frame->segsize &&
+ while(iPix <= (ov511->packet_size - 1) - frame->segsize &&
frame->segment < frame->width * frame->height / 256) {
int iSegY;
int iSegUV;
@@ -1099,7 +1157,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
/* Save extra data for next time */
if (frame->segment < frame->width * frame->height / 256) {
- ov511->scratchlen = 992 - iPix;
+ ov511->scratchlen = (ov511->packet_size - 1) - iPix;
if (ov511->scratchlen < frame->segsize) {
memmove(ov511->scratch, pData, ov511->scratchlen);
} else {
@@ -1149,13 +1207,20 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
{
urb_t *urb;
int fx, err;
-
+
+ PDEBUG(4, "ov511_init_isoc");
+
ov511->compress = 0;
ov511->curframe = -1;
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- ov511_set_packet_size(ov511, 993);
+ if (ov511->bridge == BRG_OV511)
+ ov511_set_packet_size(ov511, 993);
+ else if (ov511->bridge == BRG_OV511PLUS)
+ ov511_set_packet_size(ov511, 961);
+ else
+ err("invalid bridge type");
/* We double buffer the Iso lists */
urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1172,10 +1237,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb->transfer_buffer = ov511->sbuf[0].data;
urb->complete = ov511_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+ urb->iso_frame_desc[fx].length = ov511->packet_size;
}
urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1191,10 +1256,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb->transfer_buffer = ov511->sbuf[1].data;
urb->complete = ov511_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+ urb->iso_frame_desc[fx].length = ov511->packet_size;
}
ov511->sbuf[1].urb->next = ov511->sbuf[0].urb;
@@ -1215,6 +1280,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
static void ov511_stop_isoc(struct usb_ov511 *ov511)
{
+ PDEBUG(4, "ov511_stop_isoc");
if (!ov511->streaming || !ov511->dev)
return;
@@ -1239,10 +1305,11 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511)
static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
{
-#if 1
struct ov511_frame *frame;
int width, height;
+ PDEBUG(4, "ov511_new_frame");
+
if (!ov511->dev)
return -1;
@@ -1277,7 +1344,6 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
// /* We want a fresh frame every 30 we get */
// ov511->compress = (ov511->compress + 1) % 30;
-#endif
return 0;
}
@@ -1311,10 +1377,10 @@ static int ov511_open(struct video_device *dev, int flags)
PDEBUG(4, "frame [0] @ %p", ov511->frame[0].data);
PDEBUG(4, "frame [1] @ %p", ov511->frame[1].data);
- ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[0].data)
goto open_err_on0;
- ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[1].data)
goto open_err_on1;
@@ -1835,9 +1901,11 @@ static struct video_device ov511_template = {
initialize: ov511_init_done,
};
-static int ov7610_configure(struct usb_device *dev)
+static int ov7610_configure(struct usb_ov511 *ov511)
{
+ struct usb_device *dev = ov511->dev;
int tries;
+ int rc;
if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
OV7610_I2C_WRITE_ID) < 0)
@@ -1865,13 +1933,42 @@ static int ov7610_configure(struct usb_device *dev)
--tries;
}
- if (tries == 0) {
- err("Failed to read OV7610 ID. You might not have an OV7610,");
+ if (tries == 1) {
+ err("Failed to read sensor ID. You might not have an OV7610/20,");
err("or it may be not responding. Report this to");
err("mmcclelland@delphi.com");
return -1;
}
+ if (sensor == 0) {
+ rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
+
+ if (rc < 0) {
+ err("Error detecting sensor type");
+ return -1;
+ }
+ else if((rc & 3) == 3) {
+ printk("ov511: Sensor is an OV7610\n");
+ ov511->sensor = SEN_OV7610;
+ }
+ else if((rc & 3) == 1) {
+ printk("ov511: Sensor is an OV7620AE\n");
+ ov511->sensor = SEN_OV7620AE;
+ }
+ else if((rc & 3) == 0) {
+ printk("ov511: Sensor is an OV7620\n");
+ ov511->sensor = SEN_OV7620;
+ }
+ else {
+ err("Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+ }
+ else { /* sensor != 0; user overrode detection */
+ ov511->sensor = sensor;
+ printk("ov511: Sensor set to type %d\n", ov511->sensor);
+ }
+
return 0;
}
@@ -1890,9 +1987,9 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d},
{OV511_DONE_BUS, 0x0, 0x00},
};
- static struct ov511_regvals aRegvalsNorm[] =
- {{OV511_REG_BUS, 0x20, 1},
-#if 1
+
+ static struct ov511_regvals aRegvalsNorm7610[] =
+ {{OV511_REG_BUS, 0x20, 0x01},
{OV511_REG_BUS, 0x52, 0x02},
{OV511_REG_BUS, 0x52, 0x00},
{OV511_REG_BUS, 0x31, 0x1f}, /* 0f */
@@ -1907,16 +2004,14 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_REG_BUS, 0x78, 0x06},
{OV511_REG_BUS, 0x79, 0x03},
-
{OV511_I2C_BUS, 0x10, 0xff},
{OV511_I2C_BUS, 0x16, 0x06},
- {OV511_I2C_BUS, 0x28, 0x24}, /* 24 */
+ {OV511_I2C_BUS, 0x28, 0x24},
{OV511_I2C_BUS, 0x2b, 0xac},
{OV511_I2C_BUS, 0x05, 0x00},
{OV511_I2C_BUS, 0x06, 0x00},
{OV511_I2C_BUS, 0x12, 0x00},
-// {OV511_I2C_BUS, 0x13, 0x00},
{OV511_I2C_BUS, 0x38, 0x81},
{OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
{OV511_I2C_BUS, 0x05, 0x00},
@@ -1931,26 +2026,64 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
{OV511_I2C_BUS, 0x2a, 0x04},
{OV511_I2C_BUS, 0x2c, 0xfe},
- {OV511_I2C_BUS, 0x2d, 0x93}, /* d7 */
{OV511_I2C_BUS, 0x30, 0x71},
{OV511_I2C_BUS, 0x31, 0x60},
{OV511_I2C_BUS, 0x32, 0x26},
{OV511_I2C_BUS, 0x33, 0x20},
{OV511_I2C_BUS, 0x34, 0x48},
{OV511_I2C_BUS, 0x12, 0x24},
-// {OV511_I2C_BUS, 0x13, 0x01},
{OV511_I2C_BUS, 0x11, 0x01},
{OV511_I2C_BUS, 0x0c, 0x24},
{OV511_I2C_BUS, 0x0d, 0x24},
-#endif
{OV511_DONE_BUS, 0x0, 0x00},
};
- /* Set altsetting 0 */
- if (usb_set_interface(dev, ov511->iface, 0) < 0) {
- err("usb_set_interface error");
- return -EBUSY;
- }
+ static struct ov511_regvals aRegvalsNorm7620[] =
+ {{OV511_REG_BUS, 0x20, 0x01},
+ {OV511_REG_BUS, 0x52, 0x02},
+ {OV511_REG_BUS, 0x52, 0x00},
+ {OV511_REG_BUS, 0x31, 0x1f},
+ {OV511_REG_BUS, 0x70, 0x3f},
+ {OV511_REG_BUS, 0x71, 0x3f},
+ {OV511_REG_BUS, 0x72, 0x01},
+ {OV511_REG_BUS, 0x73, 0x01},
+ {OV511_REG_BUS, 0x74, 0x01},
+ {OV511_REG_BUS, 0x75, 0x01},
+ {OV511_REG_BUS, 0x76, 0x01},
+ {OV511_REG_BUS, 0x77, 0x01},
+ {OV511_REG_BUS, 0x78, 0x06},
+ {OV511_REG_BUS, 0x79, 0x03},
+
+ {OV511_I2C_BUS, 0x10, 0xff},
+ {OV511_I2C_BUS, 0x16, 0x06},
+ {OV511_I2C_BUS, 0x28, 0x24},
+ {OV511_I2C_BUS, 0x2b, 0xac},
+
+ {OV511_I2C_BUS, 0x12, 0x00},
+
+ {OV511_I2C_BUS, 0x28, 0x24},
+ {OV511_I2C_BUS, 0x05, 0x00},
+ {OV511_I2C_BUS, 0x0f, 0x05},
+ {OV511_I2C_BUS, 0x15, 0x01},
+ {OV511_I2C_BUS, 0x23, 0x00},
+ {OV511_I2C_BUS, 0x24, 0x10},
+ {OV511_I2C_BUS, 0x25, 0x8a},
+ {OV511_I2C_BUS, 0x26, 0xa2},
+ {OV511_I2C_BUS, 0x27, 0xe2},
+ {OV511_I2C_BUS, 0x29, 0x03},
+ {OV511_I2C_BUS, 0x2a, 0x00},
+ {OV511_I2C_BUS, 0x2c, 0xfe},
+ {OV511_I2C_BUS, 0x30, 0x71},
+ {OV511_I2C_BUS, 0x31, 0x60},
+ {OV511_I2C_BUS, 0x32, 0x26},
+ {OV511_I2C_BUS, 0x33, 0x20},
+ {OV511_I2C_BUS, 0x34, 0x48},
+ {OV511_I2C_BUS, 0x12, 0x24},
+ {OV511_I2C_BUS, 0x11, 0x01},
+ {OV511_I2C_BUS, 0x0c, 0x24},
+ {OV511_I2C_BUS, 0x0d, 0x24},
+ {OV511_DONE_BUS, 0x0, 0x00},
+ };
memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
@@ -1966,18 +2099,17 @@ static int ov511_configure(struct usb_ov511 *ov511)
if ((rc = ov511_write_regvals(dev, aRegvalsInit)))
return rc;
- if(ov7610_configure(dev) < 0) {
+ if(ov7610_configure(ov511) < 0) {
err("failed to configure OV7610");
goto error;
}
+ ov511_set_packet_size(ov511, 0);
+
/* Disable compression */
- if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
- err("disable compression: command failed");
+ if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0)
goto error;
- }
- ov511->compress = 0;
ov511->snap_enabled = snapshot;
/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
@@ -1990,15 +2122,27 @@ static int ov511_configure(struct usb_ov511 *ov511)
ov511->frame[1].bytes_read = 0;
/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
- if ((rc = ov511_write_regvals(dev, aRegvalsNorm))) goto error;
- if ((rc = ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
- VIDEO_PALETTE_RGB24, 0)) < 0) goto error;
+
+ if (ov511->sensor == SEN_OV7620) {
+ if (ov511_write_regvals(dev, aRegvalsNorm7620)) goto error;
+ }
+ else {
+ if (ov511_write_regvals(dev, aRegvalsNorm7610)) goto error;
+ }
+
+ if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ VIDEO_PALETTE_RGB24, 0) < 0) goto error;
if (autoadjust) {
if (ov511_i2c_write(dev, 0x13, 0x01) < 0) goto error;
+ if (ov511_i2c_write(dev, 0x2d,
+ ov511->sensor==SEN_OV7620?0x91:0x93) < 0) goto error;
}
else {
- if (ov511_i2c_write(dev, 0x13, 0x00) < 0 ) goto error;
+ if (ov511_i2c_write(dev, 0x13, 0x00) < 0) goto error;
+ if (ov511_i2c_write(dev, 0x2d,
+ ov511->sensor==SEN_OV7620?0x81:0x83) < 0) goto error;
+ ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
}
return 0;
@@ -2009,6 +2153,7 @@ error:
&dev->actconfig->interface[ov511->iface]);
kfree(ov511);
+ ov511 = NULL;
return -EBUSY;
}
@@ -2027,10 +2172,11 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
interface = &dev->actconfig->interface[ifnum].altsetting[0];
- /* Is it an OV511? */
+ /* Is it an OV511/OV511+? */
if (dev->descriptor.idVendor != 0x05a9)
return NULL;
- if (dev->descriptor.idProduct != 0x0511)
+ if (dev->descriptor.idProduct != 0x0511
+ && dev->descriptor.idProduct != 0xA511)
return NULL;
/* Checking vendor/product should be enough, but what the hell */
@@ -2039,9 +2185,6 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
if (interface->bInterfaceSubClass != 0x00)
return NULL;
- /* We found one */
- printk(KERN_INFO "ov511: USB OV511-based camera found\n");
-
if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
err("couldn't kmalloc ov511 struct");
return NULL;
@@ -2052,15 +2195,24 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
ov511->dev = dev;
ov511->iface = interface->bInterfaceNumber;
+ if (dev->descriptor.idProduct == 0x0511) {
+ info("USB OV511 camera found");
+ ov511->bridge = BRG_OV511;
+ }
+ else if (dev->descriptor.idProduct == 0xA511) {
+ info("USB OV511+ camera found");
+ ov511->bridge = BRG_OV511PLUS;
+ }
+
rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
if (rc < 0) {
err("Unable to read camera bridge registers");
- return NULL;
+ goto error;
}
switch(ov511->customid = rc) {
case 0: /* This also means that no custom ID was set */
- printk("ov511: Camera is probably a MediaForte MV300\n");
+ printk("ov511: Camera is a generic model (no ID)\n");
break;
case 3:
printk("ov511: Camera is a D-Link DSB-C300\n");
@@ -2077,6 +2229,11 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
case 36:
printk("ov511: Camera is a Koala-Cam\n");
break;
+ case 38:
+ printk("ov511: Camera is a Lifeview USB Life TV\n");
+ printk("ov511: This device is not supported, exiting...\n");
+ goto error;
+ break;
case 100:
printk("ov511: Camera is a Lifeview RoboCam\n");
break;
@@ -2090,9 +2247,13 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
err("Specific camera type (%d) not recognized", rc);
err("Please contact mmcclelland@delphi.com to request");
err("support for your camera.");
- return NULL;
}
+// if (ov511->bridge == BRG_OV511PLUS) {
+// err("Sorry, the OV511+ chip is not supported yet");
+// goto error;
+// }
+
if (!ov511_configure(ov511)) {
ov511->user=0;
init_MUTEX(&ov511->lock); /* to 1 == available */
@@ -2100,10 +2261,18 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
}
else {
err("Failed to configure camera");
- return NULL;
+ goto error;
}
return ov511;
+
+error:
+ if (ov511) {
+ kfree(ov511);
+ ov511 = NULL;
+ }
+
+ return NULL;
}
static void ov511_disconnect(struct usb_device *dev, void *ptr)
@@ -2147,7 +2316,7 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb(ov511->sbuf[0].urb);
usb_free_urb(ov511->sbuf[0].urb);
ov511->sbuf[0].urb = NULL;
- }
+ }
/* Free the memory */
if (!ov511->user) {
diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h
index 6a4a332bf..7e679eb40 100644
--- a/drivers/usb/ov511.h
+++ b/drivers/usb/ov511.h
@@ -1,8 +1,6 @@
#ifndef __LINUX_OV511_H
#define __LINUX_OV511_H
-//#include <linux/list.h>
-
#define OV511_DEBUG /* Turn on debug messages */
#ifdef OV511_DEBUG
@@ -75,14 +73,16 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51
#define OV511_REG_SYSTEM_SNAPSHOT 0x52
#define OV511_REG_SYSTEM_INIT 0x53
+#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+ only */
+#define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */
#define OV511_REG_SYSTEM_USER_DEFINED 0x5E
#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F
/* OmniCE register numbers */
-#define OV511_OMNICE_PREDICATION_HORIZ_Y 0x70
-#define OV511_OMNICE_PREDICATION_HORIZ_UV 0x71
-#define OV511_OMNICE_PREDICATION_VERT_Y 0x72
-#define OV511_OMNICE_PREDICATION_VERT_UV 0x73
+#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70
+#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71
+#define OV511_OMNICE_PREDICTION_VERT_Y 0x72
+#define OV511_OMNICE_PREDICTION_VERT_UV 0x73
#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74
#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75
#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76
@@ -94,15 +94,25 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_OMNICE_UV_LUT_BEGIN 0xA0
#define OV511_OMNICE_UV_LUT_END 0xBF
-/* Alternate numbers for various max packet sizes */
-#define OV511_ALTERNATE_SIZE_992 0
-#define OV511_ALTERNATE_SIZE_993 1
-#define OV511_ALTERNATE_SIZE_768 2
-#define OV511_ALTERNATE_SIZE_769 3
-#define OV511_ALTERNATE_SIZE_512 4
-#define OV511_ALTERNATE_SIZE_513 5
-#define OV511_ALTERNATE_SIZE_257 6
-#define OV511_ALTERNATE_SIZE_0 7
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992 0
+#define OV511_ALT_SIZE_993 1
+#define OV511_ALT_SIZE_768 2
+#define OV511_ALT_SIZE_769 3
+#define OV511_ALT_SIZE_512 4
+#define OV511_ALT_SIZE_513 5
+#define OV511_ALT_SIZE_257 6
+#define OV511_ALT_SIZE_0 7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0 0
+#define OV511PLUS_ALT_SIZE_33 1
+#define OV511PLUS_ALT_SIZE_129 2
+#define OV511PLUS_ALT_SIZE_257 3
+#define OV511PLUS_ALT_SIZE_385 4
+#define OV511PLUS_ALT_SIZE_513 5
+#define OV511PLUS_ALT_SIZE_769 6
+#define OV511PLUS_ALT_SIZE_961 7
/* ov7610 registers */
#define OV7610_REG_GAIN 0x00
@@ -154,7 +164,8 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define SCRATCH_BUF_SIZE 384
#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC 993 /* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */
+#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -171,6 +182,19 @@ int usb_ov511_reg_write(struct usb_device *dev,
unsigned char reg,
unsigned char value);
+/* Bridge types */
+enum {
+ BRG_OV511,
+ BRG_OV511PLUS,
+};
+
+/* Sensor types */
+enum {
+ SEN_UNKNOWN,
+ SEN_OV7610,
+ SEN_OV7620,
+ SEN_OV7620AE,
+};
enum {
STATE_SCANNING, /* Scanning for start */
@@ -214,7 +238,7 @@ struct ov511_frame {
int hdrheight; /* Height */
int sub_flag; /* Sub-capture mode for this frame? */
- int format; /* Format for this frame */
+ int format; /* Format for this frame */
int segsize; /* How big is each segment from the camera? */
volatile int grabstate; /* State of grabbing */
@@ -274,6 +298,11 @@ struct usb_ov511 {
wait_queue_head_t wq; /* Processes waiting */
int snap_enabled; /* Snapshot mode enabled */
+
+ int bridge; /* Type of bridge (OV511 or OV511+) */
+ int sensor; /* Type of image sensor chip */
+
+ int packet_size; /* Frame size per isoc desc */
};
#endif
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 764f1c055..d16a65725 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -16,11 +16,13 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500
-#define PEGASUS_MAX_MTU 1536
+#define PEGASUS_MAX_MTU 1536
+#define SROM_WRITE 0x01
+#define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
#define ALIGN(x) x __attribute__((aligned(16)))
@@ -51,12 +53,18 @@ MODULE_PARM(loopback, "i");
static struct usb_eth_dev usb_dev_id[] = {
- { "D-Link DSB-650TX", 0x2001, 0x4001, NULL },
- { "Linksys USB100TX", 0x066b, 0x2203, NULL },
- { "SMC 202 USB Ethernet", 0x0707, 0x0200, NULL },
- { "ADMtek AN986 (Pegasus) USB Ethernet", 0x07a6, 0x0986, NULL },
- { "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL },
- { NULL, 0, 0, NULL }
+ {"Billionton USB-100", 0x08dd, 0x0986, NULL},
+ {"Corega FEter USB-TX", 0x7aa, 0x0004, NULL},
+ {"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, NULL},
+ {"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
+ {"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
+ {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
+ {"Linksys USB100TX", 0x066b, 0x2203, NULL},
+ {"Linksys USB100TX", 0x066b, 0x2204, NULL},
+ {"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL},
+ {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL},
+ {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
+ {NULL, 0, 0, NULL}
};
@@ -105,10 +113,10 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
return 1;
}
-static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata)
+static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
- __u8 data[4] = { index, 0, 0, 0x02 };
+ __u8 data[4] = { index, 0, 0, direction };
pegasus_set_registers(dev, 0x20, 4, data);
for (i = 0; i < 100; i++) {
@@ -120,7 +128,7 @@ static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *ret
}
}
- warn("read_srom_word() failed");
+ warn("pegasus_rw_srom_word() failed");
return 1;
}
@@ -128,7 +136,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
{
int i;
for (i = 0; i < 3; i++)
- if (pegasus_read_srom_word(dev, i, (__u16 *)&id[i * 2]))
+ if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
return 1;
return 0;
}
@@ -170,8 +178,9 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
return 2;
if ((~temp & 4) && !loopback) {
- err("link NOT established - %x", temp);
- return 3;
+ warn("%s: link NOT established (0x%x), check the cable.",
+ dev->name, temp);
+ /* return 3; FIXME */
}
if (pegasus_read_phy_word(usb, 5, &partmedia))
@@ -376,13 +385,14 @@ static void pegasus_set_rx_mode(struct net_device *net)
if (net->flags & IFF_PROMISC) {
info("%s: Promiscuous mode enabled", net->name);
- pegasus_set_register(pegasus->usb, 2, 0x04);
+/* pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
pegasus_set_register(pegasus->usb, 0, 0xfa);
pegasus_set_register(pegasus->usb, 2, 0);
+ info("%s set allmulti", net->name);
} else {
- dbg("%s: set Rx mode", net->name);
+ info("%s: set Rx mode", net->name);
}
netif_wake_queue(net);
@@ -395,18 +405,19 @@ static int check_device_ids( __u16 vendor, __u16 product )
while ( usb_dev_id[i].name ) {
if ( (usb_dev_id[i].vendor == vendor) &&
(usb_dev_id[i].device == product) )
- return 0;
+ return i;
i++;
}
- return 1;
+ return -1;
}
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
struct pegasus *pegasus;
+ int dev_indx;
- if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) {
+ if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
return NULL;
}
@@ -449,11 +460,11 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
pegasus);
- FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 0),
+ FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
pegasus->intr_buff, 8, pegasus_irq, pegasus, 250);
- printk(KERN_INFO "%s: ADMtek AN986 Pegasus usb device\n", net->name);
+ printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
return pegasus;
}
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 4c100f16c..c1a7ddb67 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -160,10 +160,13 @@ static int usblp_open(struct inode *inode, struct file *file)
if (usblp->used)
return -EBUSY;
- if ((retval = usblp_check_status(usblp)))
+ MOD_INC_USE_COUNT;
+
+ if ((retval = usblp_check_status(usblp))) {
+ MOD_DEC_USE_COUNT;
return retval;
+ }
- MOD_INC_USE_COUNT;
usblp->used = 1;
file->private_data = usblp;
@@ -179,17 +182,18 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
- MOD_DEC_USE_COUNT;
usblp->used = 0;
if (usblp->dev) {
usb_unlink_urb(&usblp->readurb);
usb_unlink_urb(&usblp->writeurb);
+ MOD_DEC_USE_COUNT;
return 0;
}
usblp_table[usblp->minor] = NULL;
kfree(usblp);
+ MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index 4c69d4221..666752f76 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -1,7 +1,7 @@
/* -*- linux-c -*- */
/*
- * Driver for USB Scanners (linux-2.3.42)
+ * Driver for USB Scanners (linux-2.3.99-pre3-7)
*
* Copyright (C) 1999, 2000 David E. Nelson
*
@@ -148,8 +148,29 @@
* - Increased the timeout parameter in read_scanner() to 120 Secs.
*
*
+ * 0.4.2 3/23/2000
+ *
+ * - Added Umax 1236U ID. Thanks to Philipp Baer <ph_baer@npw.net>.
+ * - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
+ * Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
+ * - Fixed error number reported for non-existant devices. Thanks to
+ * Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
+ * - Added Acer Prisascan 620U ID's. Thanks to Joao <joey@knoware.nl>.
+ * - Replaced __initcall() with module_init()/module_exit(). Updates
+ * from patch-2.3.48.
+ * - Replaced file_operations structure with new syntax. Updates
+ * from patch-2.3.49.
+ * - Changed #include "usb.h" to #include <linux/usb.h>
+ * - Added #define SCN_IOCTL to exclude development areas
+ * since 2.4.x is about to be released. This mainly affects the
+ * ioctl() stuff. See scanner.h for more details.
+ * - Changed the return value for signal_pending() from -ERESTARTSYS to
+ * -EINTR.
+ *
+ *
* TODO
*
+ * - Performance
* - Select/poll methods
* - More testing
* - Proper registry/assignment for LM9830 ioctl's
@@ -214,7 +235,7 @@ open_scanner(struct inode * inode, struct file * file)
if (!p_scn_table[scn_minor]) {
err("open_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
scn = p_scn_table[scn_minor];
@@ -255,7 +276,7 @@ close_scanner(struct inode * inode, struct file * file)
if (!p_scn_table[scn_minor]) {
err("close_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
scn = p_scn_table[scn_minor];
@@ -279,6 +300,8 @@ write_scanner(struct file * file, const char * buffer,
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
+ kdev_t scn_minor;
+
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
int result = 0;
@@ -287,6 +310,8 @@ write_scanner(struct file * file, const char * buffer,
scn = file->private_data;
+ scn_minor = scn->scn_minor;
+
obuf = scn->obuf;
dev = scn->scn_dev;
@@ -294,7 +319,7 @@ write_scanner(struct file * file, const char * buffer,
while (count > 0) {
if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ ret = -EINTR;
break;
}
@@ -306,14 +331,14 @@ write_scanner(struct file * file, const char * buffer,
}
result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
- dbg("write stats(%d): result:%d this_write:%d partial:%d", scn->scn_minor, result, this_write, partial);
+ dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK recieved.");
ret = -ETIME;
break;
} else if (result < 0) { /* We should not get any I/O errors */
- warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn->scn_minor, result);
+ warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
ret = -EIO;
break;
}
@@ -322,7 +347,7 @@ write_scanner(struct file * file, const char * buffer,
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
- printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+ printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", obuf[cnt]);
}
@@ -355,8 +380,10 @@ read_scanner(struct file * file, char * buffer,
struct scn_usb_data *scn;
struct usb_device *dev;
- ssize_t bytes_read = 0; /* Overall count of bytes_read */
- ssize_t ret = 0;
+ ssize_t bytes_read; /* Overall count of bytes_read */
+ ssize_t ret;
+
+ kdev_t scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
@@ -366,29 +393,32 @@ read_scanner(struct file * file, char * buffer,
scn = file->private_data;
+ scn_minor = scn->scn_minor;
+
ibuf = scn->ibuf;
dev = scn->scn_dev;
bytes_read = 0;
+ ret = 0;
while (count) {
if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ ret = -EINTR;
break;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 120*HZ);
- dbg("read stats(%d): result:%d this_read:%d partial:%d", scn->scn_minor, result, this_read, partial);
+ dbg("read stats(%d): result:%d this_read:%d partial:%d", scn_minor, result, this_read, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
- warn("read_scanner(%d): NAK received", scn->scn_minor);
+ warn("read_scanner(%d): NAK received", scn_minor);
ret = -ETIME;
break;
} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
- warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn->scn_minor, (int)result);
+ warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
ret = -EIO;
break;
}
@@ -397,7 +427,7 @@ read_scanner(struct file * file, char * buffer,
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
- printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+ printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", ibuf[cnt]);
}
@@ -492,15 +522,17 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
if (dev->descriptor.idVendor == 0x1606) { /* Umax */
if (dev->descriptor.idProduct == 0x0010 || /* Astra 1220U */
- dev->descriptor.idProduct == 0x0030) { /* Astra 2000U */
+ dev->descriptor.idProduct == 0x0030 || /* Astra 2000U */
+ dev->descriptor.idProduct == 0x0002) { /* Astra 1236U */
valid_device = 1;
break;
}
}
if (dev->descriptor.idVendor == 0x04b8) { /* Seiko/Epson Corp. */
- if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636 */
- dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U */
+ if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636U and 636Photo */
+ dev->descriptor.idProduct == 0x0103 || /* Perfection 610 */
+ dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U and 1200Photo */
valid_device = 1;
break;
}
@@ -526,15 +558,56 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
}
}
+ if (dev->descriptor.idVendor == 0x0461) { /* Primax/Colorado */
+ if (dev->descriptor.idProduct == 0x0300 || /* G2-300 #1 */
+ dev->descriptor.idProduct == 0x0380 || /* G2-600 #1 */
+ dev->descriptor.idProduct == 0x0301 || /* G2E-300 */
+ dev->descriptor.idProduct == 0x0381 || /* ReadyScan 636i */
+ dev->descriptor.idProduct == 0x0302 || /* G2-300 #2 */
+ dev->descriptor.idProduct == 0x0382 || /* G2-600 #2 */
+ dev->descriptor.idProduct == 0x0303 || /* G2E-300 */
+ dev->descriptor.idProduct == 0x0383 || /* G2E-600 */
+ dev->descriptor.idProduct == 0x0340 || /* Colorado USB 9600 */
+ dev->descriptor.idProduct == 0x0360 || /* Colorado USB 19200 */
+ dev->descriptor.idProduct == 0x0341 || /* Colorado 600u */
+ dev->descriptor.idProduct == 0x0361) { /* Colorado 1200u */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x04a7) { /* Visioneer */
+ if (dev->descriptor.idProduct == 0x0221 || /* OneTouch 5300 */
+ dev->descriptor.idProduct == 0x0221 || /* OneTouch 7600 */
+ dev->descriptor.idProduct == 0x0231) { /* 6100 */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x0458) { /* Genius */
+ if(dev->descriptor.idProduct == 0x2001) { /* ColorPage-Vivid Pro */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x04a5) { /* Acer */
+ if(dev->descriptor.idProduct == 0x2060) { /* Prisa Acerscan 620U */
+ valid_device = 1;
+ break;
+ }
+ }
+
if (dev->descriptor.idVendor == vendor && /* User specified */
dev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
break;
}
-
-
+
+
} while (0);
-
+
if (!valid_device)
return NULL; /* We didn't find anything pleasing */
@@ -714,6 +787,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
kfree (scn);
}
+#ifdef SCN_IOCTL
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
@@ -728,7 +802,7 @@ ioctl_scanner(struct inode *inode, struct file *file,
if (!p_scn_table[scn_minor]) {
err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
dev = p_scn_table[scn_minor]->scn_dev;
@@ -790,12 +864,15 @@ ioctl_scanner(struct inode *inode, struct file *file,
}
return 0;
}
+#endif /* SCN_IOCTL */
static struct
file_operations usb_scanner_fops = {
read: read_scanner,
write: write_scanner,
+#ifdef SCN_IOCTL
ioctl: ioctl_scanner,
+#endif /* SCN_IOCTL */
open: open_scanner,
release: close_scanner,
};
@@ -810,12 +887,14 @@ usb_driver scanner_driver = {
SCN_BASE_MNR
};
-void __exit usb_scanner_exit(void)
+void __exit
+usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
-int __init usb_scanner_init(void)
+int __init
+usb_scanner_init (void)
{
if (usb_register(&scanner_driver) < 0)
return -1;
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index ed8320424..d4dd607b7 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -6,8 +6,15 @@
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
+
// #define DEBUG
+
+/* Enable to activate the ioctl interface. This is mainly meant for */
+/* development purposes until an ioctl number is officially registered */
+// #define SCN_IOCTL
+
#include <linux/usb.h>
+// #include "usb.h"
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 02bd7aad6..95a686e7a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -1,67 +1,11 @@
#
-# Makefile for the kernel USB device drivers.
+# Makefile for the USB serial device drivers.
#
-# Subdirs.
-
-SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-MOD_IN_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-# The target object and module list name.
-
-O_TARGET := serial.o
+O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usb-serial.o
+O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
MOD_LIST_NAME := USB_SERIAL_MODULES
-# Objects that export symbols.
-
-# Multipart objects.
-
-# Optional parts of multipart objects.
-
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_USB_SERIAL) += usb-serial.o
-
-# Extract lists of the multi-part drivers.
-# The 'int-*' lists are the intermediate files used to build the multi's.
-
-multi-y := $(filter $(list-multi), $(obj-y))
-multi-m := $(filter $(list-multi), $(obj-m))
-int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-
-# Files that are both resident and modular: remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-int-m := $(filter-out $(int-y), $(int-m))
-
-# Take multi-part drivers out of obj-y and put components in.
-
-obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-
-# The global Rules.make.
-
include $(TOPDIR)/Rules.make
-# Link rules for multi-part drivers.
-
diff --git a/drivers/usb/serial/ezusb_convert.pl b/drivers/usb/serial/ezusb_convert.pl
index b4f08b2d7..3c69e4c1c 100644
--- a/drivers/usb/serial/ezusb_convert.pl
+++ b/drivers/usb/serial/ezusb_convert.pl
@@ -27,6 +27,8 @@ while (<STDIN>) {
push(@records, [$addr, \@bytes]);
}
+@sorted_records = sort { $a->[0] <=> $b->[0] } @records;
+
print <<"EOF";
/*
* ${basename}_fw.h
@@ -39,7 +41,7 @@ print <<"EOF";
EOF
print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n";
-foreach $r (@records) {
+foreach $r (@sorted_records) {
printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]}));
print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]});
print "} },\n";
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
new file mode 100644
index 000000000..151c4bfe7
--- /dev/null
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -0,0 +1,728 @@
+/*
+ * USB FTDI SIO driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ * Bill Ryder (bryder@sgi.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (04/04/2000) Bill Ryder
+ * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
+ * handled elsewhere in the serial driver chain).
+ *
+ * (03/30/2000) Bill Ryder
+ * Implemented lots of ioctls
+ * Fixed a race condition in write
+ * Changed some dbg's to errs
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/* to talk to the device */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+
+#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 "ftdi_sio.h"
+
+#define FTDI_VENDOR_ID 0x0403
+#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
+
+/* function prototypes for a FTDI serial converter */
+static int ftdi_sio_startup (struct usb_serial *serial);
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp);
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp);
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void ftdi_sio_write_bulk_callback (struct urb *urb);
+static void ftdi_sio_read_bulk_callback (struct urb *urb);
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old);
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+
+/* All of the device info needed for the FTDI SIO serial converter */
+static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
+static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
+struct usb_serial_device_type ftdi_sio_device = {
+ name: "FTDI SIO",
+ idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */
+ idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */
+ needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: ftdi_sio_open,
+ close: ftdi_sio_close,
+ write: ftdi_sio_write,
+ read_bulk_callback: ftdi_sio_read_bulk_callback,
+ write_bulk_callback: ftdi_sio_write_bulk_callback,
+ ioctl: ftdi_sio_ioctl,
+ set_termios: ftdi_sio_set_termios,
+ startup: ftdi_sio_startup,
+};
+
+
+/*
+ * ***************************************************************************
+ * FTDI SIO Serial Converter specific driver functions
+ * ***************************************************************************
+ *
+ * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
+ * Thanx to FTDI for so kindly providing details of the protocol required
+ * to talk to the device - http://www.ftdi.co.uk
+ *
+ * Tested as at this version - other stuff might work
+ * 23 March 2000
+ * Works:
+ * Baudrates - 9600, 38400,19200, 57600, 115200
+ * TIOCMBIC - TIOCM_DTR / TIOCM_RTS
+ * TIOCMBIS - TIOCM_DTR / TIOCM_RTS
+ * TIOCMSET - DTR on/RTSon / DTR off, RTS off
+ * no parity:CS8 even parity:CS7 odd parity:CS7
+ * CRTSCTS flow control
+ *
+ * Pilot-xfer zillions of times
+ *
+ * cu works with dir option
+ *
+ * Not Tested (ie might not work):
+ * xon/xoff flow control
+ * ppp (modem handling in general)
+ *
+ * KNOWN BUGS:
+ * Multiple Opens
+ * ==============
+ * Seems to have problem when opening an already open port,
+ * Get I/O error on first attempt, then it lets you in.
+ * Need to do proper usage counting - keep registered callbacks for first opener.
+ *
+ * Reproduce with:
+ * cu -l /dev/ttyUSB0 dir
+ * whilst cu is running do:
+ * stty -a < /dev/ttyUSB0
+ *
+ * from stty get: 'bash: /dev/ttyUSB0: Invalid argument '
+ * from cu get
+ * write: Invalid argument
+ *
+ * Initialisation Problem
+ * ======================
+ * Pilot transfer required me to run the serial_loopback program before it would work.
+ * Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
+ *
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int ftdi_sio_startup (struct usb_serial *serial)
+{
+ init_waitqueue_head(&serial->write_wait);
+
+ return (0);
+}
+
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_open */
+ struct termios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ char buf[1]; /* Needed for the usb_control_msg I think */
+
+ dbg("ftdi_sio_open port %d", port->number);
+
+ /* FIXME - multiple concurrent opens cause trouble */
+ if (port->active) {
+ err ("port already open");
+ return -EINVAL;
+ }
+ port->active = 1; /* FIXME - For multiple open this should increment */
+
+ /* See ftdi_sio.h for description of what is reset */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
+ 0, buf, 0, WDR_TIMEOUT);
+
+ /* Setup termios */
+ port->tty->termios->c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+
+ ftdi_sio_set_termios(port, &tmp_termios);
+
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+ return(-EINVAL);
+ }
+
+ /* Turn on RTS and DTR since we are not flow controlling*/
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR HIGH urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS HIGH urb");
+ }
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ err("usb_submit_urb(read bulk) failed");
+
+ return (0);
+} /* ftdi_sio_open */
+
+
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_close */
+ struct usb_serial *serial = port->serial;
+ unsigned int c_cflag = port->tty->termios->c_cflag;
+ char buf[1];
+
+ dbg("ftdi_sio_close port %d", port->number);
+
+ if (c_cflag & HUPCL){
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+ }
+
+ /* drop DTR */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR LOW urb");
+ }
+ /* drop RTS */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS LOW urb");
+ }
+ }
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+} /* ftdi_sio_close */
+
+
+
+/* The ftdi_sio requires the first byte to have:
+ * B0 1
+ * B1 0
+ * B2..7 length of message excluding byte 0
+ */
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{ /* ftdi_sio_write */
+ struct usb_serial *serial = port->serial;
+ const int data_offset = 1;
+ int rc;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+
+ if (count == 0) {
+ err("write request of 0 bytes");
+ return 0;
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ unsigned char *first_byte = port->write_urb->transfer_buffer;
+
+ /* Was seeing a race here, got a read callback, then write callback before
+ hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */
+
+ add_wait_queue(&serial->write_wait, &wait);
+ set_current_state (TASK_INTERRUPTIBLE);
+ while (port->write_urb->status == -EINPROGRESS) {
+ dbg("ftdi_sio - write in progress - retrying");
+ if (0 /* file->f_flags & O_NONBLOCK */) {
+ rc = -EAGAIN;
+ goto err;
+ }
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serial->write_wait, &wait);
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ schedule();
+ }
+ remove_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ count += data_offset;
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+ if (count == 0) {
+ return 0;
+ }
+
+ /* Copy in the data to send */
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer + data_offset ,
+ buf, count - data_offset );
+ }
+ else {
+ memcpy(port->write_urb->transfer_buffer + data_offset,
+ buf, count - data_offset );
+ }
+
+ /* Write the control byte at the front of the packet*/
+ first_byte = port->write_urb->transfer_buffer;
+ *first_byte = 1 | ((count-data_offset) << 2) ;
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+ if (count) {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ( "0x%02x ", first_byte[i]);
+ if (first_byte[i] > ' ' && first_byte[i] < '~') {
+ printk( "%c ", first_byte[i]);
+ } else {
+ printk( " ");
+ }
+ }
+
+
+ printk ( "\n");
+ }
+
+#endif
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ err("usb_submit_urb(write bulk) failed");
+
+ dbg("write returning: %d", count - data_offset);
+ return (count - data_offset);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return 0;
+ err: /* error exit */
+ return(rc);
+} /* ftdi_sio_write */
+
+static void ftdi_sio_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty = port->tty;
+
+ dbg("ftdi_sio_write_bulk_callback");
+
+ if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ wake_up_interruptible(&serial->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);
+
+ return;
+} /* ftdi_sio_write_bulk_callback */
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty = port->tty ;
+ unsigned char *data = urb->transfer_buffer;
+
+ const int data_offset = 2;
+ int i;
+
+ dbg("ftdi_sio read callback");
+
+ if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
+ /* TO DO -- check for hung up line and handle appropriately: */
+ /* send hangup (need to find out how to do this) */
+
+
+ if (urb->status) {
+ /* This will happen at close every time so it is a dbg not an err */
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ if (urb->actual_length > 2) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ( "0x%.2x ", data[i]);
+ if (data[i] > ' ' && data[i] < '~') {
+ printk( "%c ", data[i]);
+ } else {
+ printk( " ");
+ }
+ }
+ printk ( "\n");
+ } else {
+ dbg("Just status");
+ }
+#endif
+
+
+ if (urb->actual_length > data_offset) {
+ for (i = data_offset ; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ err("failed resubmitting read urb");
+
+ return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+/* As I understand this - old_termios contains the original termios settings */
+/* and tty->termios contains the new setting to be used */
+/* */
+/* WARNING: set_termios calls this with old_termios in kernel space */
+
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* ftdi_sio_set_termios */
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ __u16 urb_value; /* Will hold the new flags */
+ char buf[1]; /* Perhaps I should dynamically alloc this? */
+
+ dbg("ftdi_sio_set_termios port %d", port->number);
+
+
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless - should be able to
+ compare old_termios and tty->termios */
+ /* NOTE These routines can get interrupted by
+ ftdi_sio_read_bulk_callback - need to examine what this
+ means - don't see any problems yet */
+
+ /* Set number of data bits, parity, stop bits */
+
+ urb_value = 0;
+ urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+ FTDI_SIO_SET_DATA_STOP_BITS_1);
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ FTDI_SIO_SET_DATA_PARITY_EVEN) :
+ FTDI_SIO_SET_DATA_PARITY_NONE);
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+ case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+ case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+ case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+ default:
+ err("CSIZE was set but not CS5-CS8");
+ }
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, 100) < 0) {
+ err("FAILED to set databits/stopbits/parity");
+ }
+
+ /* Now do the baudrate */
+
+ switch(cflag & CBAUD){
+ case B0: break; /* Handled below */
+ case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+ case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+ case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+ case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+ case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+ case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+ case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+ case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+ case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+ case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+ default: dbg("FTDI_SIO does not support the baudrate requested");
+ /* FIXME - how to return an error for this? */ break;
+ }
+ if ((cflag & CBAUD) == B0 ) {
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from disable flowcontrol urb");
+ }
+ /* Drop RTS and DTR */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR LOW urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS LOW urb");
+ }
+
+ } else {
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ urb_value, 0,
+ buf, 0, 100) < 0) {
+ err("urb failed to set baurdrate");
+ }
+ }
+ /* Set flow control */
+ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+ if (cflag & CRTSCTS) {
+ dbg("Setting to CRTSCTS flow control");
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0 , FTDI_SIO_RTS_CTS_HS,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to set to rts/cts flow control");
+ }
+
+ } else {
+ /* CHECK Assuming XON/XOFF handled by stack - not by device */
+ /* Disable flow control */
+ dbg("Turning off hardware flow control");
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to clear flow control");
+ }
+
+ }
+ return;
+} /* ftdi_sio_set_termios */
+
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ __u16 urb_value=0; /* Will hold the new flags */
+ char buf[1];
+ int ret, mask;
+
+ dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+
+ case TIOCMGET:
+ dbg("TIOCMGET");
+ /* Request the status from the device */
+ if ((ret = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, 0,
+ buf, 1, HZ * 5)) < 0 ) {
+ dbg("Get not get modem status of device");
+ return(ret);
+ }
+
+ return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+ (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+ (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
+ (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
+ (unsigned long *) arg);
+ break;
+
+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+ dbg("TIOCMSET");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set DTR failed");
+ return(ret);
+ }
+ urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set RTS failed");
+ return(ret);
+ }
+ break;
+
+ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+ dbg("TIOCMBIS");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (mask & TIOCM_DTR){
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_DTR_HIGH , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set DTR failed");
+ return(ret);
+ }
+ }
+ if (mask & TIOCM_RTS) {
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_RTS_HIGH , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set RTS failed");
+ return(ret);
+ }
+ }
+ break;
+
+ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+ dbg("TIOCMBIC");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (mask & TIOCM_DTR){
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_DTR_LOW , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to unset DTR failed");
+ return(ret);
+ }
+ }
+ if (mask & TIOCM_RTS) {
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_RTS_LOW , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to unset RTS failed");
+ return(ret);
+ }
+ }
+ break;
+
+ /*
+ * I had originally implemented TCSET{A,S}{,F,W} and
+ * TCGET{A,S} here separately, however when testing I
+ * found that the higher layers actually do the termios
+ * conversions themselves and pass the call onto
+ * ftdi_sio_set_termios.
+ *
+ */
+
+ default:
+ /* This is not an error - turns out the higher layers will do
+ * some ioctls itself (see comment above)
+ */
+ dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ dbg("ftdi_sio_ioctl returning 0");
+ return 0;
+} /* ftdi_sio_ioctl */
+
+#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
+
+
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 36fa7bb3e..fe5f545db 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -1,15 +1,23 @@
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/* http://www.ftdi.co.uk */
-
-/* The implementation of the device I have is called a USC-1000 */
-/* which is available from http://www.dse.co.nz - cat no XH4214 */
-/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */
-/* There are other USC-1000s which don't look like my device though so beware */
-
-/* Definitions for the FTDI USB Single Port Serial Converter */
-/* known as FTDI_SIO (Serial Input/Output application of the chipset) */
+/*
+ * Definitions for the FTDI USB Single Port Serial Converter -
+ * known as FTDI_SIO (Serial Input/Output application of the chipset)
+ *
+ * The example I have is known as the USC-1000 which is available from
+ * http://www.dse.co.nz - cat no XH4214 It looks similar to this:
+ * http://www.dansdata.com/usbser.htm but I can't be sure There are other
+ * USC-1000s which don't look like my device though so beware!
+ *
+ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side,
+ * USB on the other.
+ *
+ * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details
+ * of the protocol required to talk to the device and ongoing assistence
+ * during development.
+ *
+ * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
+ * FTDI_SIO implementation.
+ *
+ */
#define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id */
@@ -27,7 +35,7 @@
/* Port Identifier Table */
#define PIT_DEFAULT 0 /* SIOA */
#define PIT_SIOA 1 /* SIOA */
-/* The device this is tested with one has one port */
+/* The device this driver is tested with one has only one port */
#define PIT_SIOB 2 /* SIOB */
#define PIT_PARALLEL 3 /* Parallel */
@@ -37,17 +45,31 @@
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
-/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_RESET
- wValue: Control Value
- 0 = Reset SIO
- 1 = Purge RX buffer
- 2 = Purge TX buffer
- wIndex: Port
- wLength: 0
- Data: None
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_RESET
+ * wValue: Control Value
+ * 0 = Reset SIO
+ * 1 = Purge RX buffer
+ * 2 = Purge TX buffer
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * The Reset SIO command has this effect:
+ *
+ * Sets flow control set to 'none'
+ * Event char = $0D
+ * Event trigger = disabled
+ * Purge RX buffer
+ * Purge TX buffer
+ * Clear DTR
+ * Clear RTS
+ * baud and data format not reset
+ *
+ * The Purge RX and TX buffer commands affect nothing except the buffers
+ *
*/
/* FTDI_SIO_SET_BAUDRATE */
@@ -55,13 +77,13 @@
#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_SET_BAUDRATE
- wValue: BaudRate value - see below
- wIndex: Port
- wLength: 0
- Data: None
-*/
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_BAUDRATE
+ * wValue: BaudRate value - see below
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ */
typedef enum {
ftdi_sio_b300 = 0,
@@ -89,28 +111,30 @@ typedef enum {
/* FTDI_SIO_SET_DATA */
-/* BmRequestType: 0100 0000B */
-/* bRequest: FTDI_SIO_SET_DATA */
-/* wValue: Data characteristics (see below) */
-/* wIndex: Port */
-/* wLength: 0 */
-/* Data: None */
-/*
- Data characteristics
-
-B0..7 Number of data bits
-B8..10 Parity
- 0 = None
- 1 = Odd
- 2 = Even
- 3 = Mark
- 4 = Space
- B11..13 Stop Bits
- 0 = 1
- 1 = 1.5
- 2 = 2
- B14..15 Reserved
-*/
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_DATA
+ * wValue: Data characteristics (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: No
+ *
+ * Data characteristics
+ *
+ * B0..7 Number of data bits
+ * B8..10 Parity
+ * 0 = None
+ * 1 = Odd
+ * 2 = Even
+ * 3 = Mark
+ * 4 = Space
+ * B11..13 Stop Bits
+ * 0 = 1
+ * 1 = 1.5
+ * 2 = 2
+ * B14..15 Reserved
+ *
+ */
@@ -119,16 +143,17 @@ B8..10 Parity
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_MODEM_CTRL
- wValue: ControlValue (see below)
- wIndex: Port
- wLength: 0
- Data: None
-
- NOTE: If the device is in RTS/CTS flow control, the RTS set by this
- command will be IGNORED without an error being returned
-*/
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_MODEM_CTRL
+ * wValue: ControlValue (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ * command will be IGNORED without an error being returned
+ * Also - you can not set DTR and RTS with one control message
+ */
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
@@ -137,100 +162,107 @@ B8..10 Parity
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
-/* ControlValue
- B0 DTR state
- 0 = reset
- 1 = set
- B1 RTS state
- 0 = reset
- 1 = set
- B2..7 Reserved
- B8 DTR state enable
- 0 = ignore
- 1 = use DTR state
- B9 RTS state enable
- 0 = ignore
- 1 = use RTS state
- B10..15 Reserved
-*/
+/*
+ * ControlValue
+ * B0 DTR state
+ * 0 = reset
+ * 1 = set
+ * B1 RTS state
+ * 0 = reset
+ * 1 = set
+ * B2..7 Reserved
+ * B8 DTR state enable
+ * 0 = ignore
+ * 1 = use DTR state
+ * B9 RTS state enable
+ * 0 = ignore
+ * 1 = use RTS state
+ * B10..15 Reserved
+ */
/* FTDI_SIO_SET_FLOW_CTRL */
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
-#define FTDI_SIO_RTS_CTS_HS 0x1
-#define FTDI_SIO_DTR_DSR_HS 0x2
-#define FTDI_SIO_XON_XOFF_HS 0x4
-/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_FLOW_CTRL
- wValue: Xoff/Xon
- wIndex: Protocol/Port - hIndex is protocl / lIndex is port
- wLength: 0
- Data: None
-
-hIndex - protocol has
- B0 Output handshaking using RTS/CTS
- 0 = disabled
- 1 = enabled
- B1 Output handshaking using DTR/DSR
- 0 = disabled
- 1 = enabled
- B2 Xon/Xoff handshaking
- 0 = disabled
- 1 = enabled
-
-A value of zero in the hIndex field selects no handshaking
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+/*
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_FLOW_CTRL
+ * wValue: Xoff/Xon
+ * wIndex: Protocol/Port - hIndex is protocl / lIndex is port
+ * wLength: 0
+ * Data: None
+ *
+ * hIndex protocol is:
+ * B0 Output handshaking using RTS/CTS
+ * 0 = disabled
+ * 1 = enabled
+ * B1 Output handshaking using DTR/DSR
+ * 0 = disabled
+ * 1 = enabled
+ * B2 Xon/Xoff handshaking
+ * 0 = disabled
+ * 1 = enabled
+ *
+ * A value of zero in the hIndex field disables handshaking
+ *
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character
+ * and the lValue field contains the XON character.
+ */
+
+/*
+ * FTDI_SIO_SET_EVENT_CHAR
+ *
+ * Set the special event character for the specified communications port.
+ * If the device sees this character it will immediately return the
+ * data read so far - rather than wait 40ms or until 62 bytes are read
+ * which is what normally happens.
+ */
-If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character
-and the lValue field contains the Xon character.
-*/
-
-/* FTDI_SIO_SET_EVENT_CHAR */
-/* Set the special event character for the specified communications port */
-/* If the device sees this character it will immediately return the */
-/* data read so far - rather than wait 40ms or until 62 bytes is read */
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_EVENT_CHAR
- wValue: EventChar
- wIndex: Port
- wLength: 0
- Data: None
-
-wValue:
- B0..7 Event Character
- B8 Event Character Processing
- 0 = disabled
- 1 = enabled
- B9..15 Reserved
-
-*/
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_EVENT_CHAR
+ * wValue: EventChar
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * wValue:
+ * B0..7 Event Character
+ * B8 Event Character Processing
+ * 0 = disabled
+ * 1 = enabled
+ * B9..15 Reserved
+ *
+ */
/* FTDI_SIO_SET_ERROR_CHAR */
+
/* Set the parity error replacement character for the specified communications port */
/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_EVENT_CHAR
- wValue: Error Char
- wIndex: Port
- wLength: 0
- Data: None
-
-Error Char
- B0..7 Error Character
- B8 Error Character Processing
- 0 = disabled
- 1 = enabled
- B9..15 Reserved
-
-*/
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_EVENT_CHAR
+ * wValue: Error Char
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ *Error Char
+ * B0..7 Error Character
+ * B8 Error Character Processing
+ * 0 = disabled
+ * 1 = enabled
+ * B9..15 Reserved
+ *
+ */
/* FTDI_SIO_GET_MODEM_STATUS */
/* Retreive the current value of the modem status register */
@@ -242,139 +274,140 @@ Error Char
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
/*
- BmRequestType: 1100 0000b
- bRequest: FTDI_SIO_GET_MODEM_STATUS
- wValue: zero
- wIndex: Port
- wLength: 1
- Data: Status
-
-One byte of data is returned
-B0..3 0
-B4 CTS
- 0 = inactive
- 1 = active
-B5 DSR
- 0 = inactive
- 1 = active
-B6 Ring Indicator (RI)
- 0 = inactive
- 1 = active
-B7 Receive Line Signal Detect (RLSD)
- 0 = inactive
- 1 = active
-*/
+ * BmRequestType: 1100 0000b
+ * bRequest: FTDI_SIO_GET_MODEM_STATUS
+ * wValue: zero
+ * wIndex: Port
+ * wLength: 1
+ * Data: Status
+ *
+ * One byte of data is returned
+ * B0..3 0
+ * B4 CTS
+ * 0 = inactive
+ * 1 = active
+ * B5 DSR
+ * 0 = inactive
+ * 1 = active
+ * B6 Ring Indicator (RI)
+ * 0 = inactive
+ * 1 = active
+ * B7 Receive Line Signal Detect (RLSD)
+ * 0 = inactive
+ * 1 = active
+ */
/* Descriptors returned by the device
+ *
+ * Device Descriptor
+ *
+ * Offset Field Size Value Description
+ * 0 bLength 1 0x12 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x01 DEVICE Descriptor Type
+ * 2 bcdUSB 2 0x0110 USB Spec Release Number
+ * 4 bDeviceClass 1 0x00 Class Code
+ * 5 bDeviceSubClass 1 0x00 SubClass Code
+ * 6 bDeviceProtocol 1 0x00 Protocol Code
+ * 7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0
+ * 8 idVendor 2 0x0403 Vendor ID
+ * 10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID)
+ * 12 bcdDevice 2 0x0001 Device release number
+ * 14 iManufacturer 1 0x01 Index of man. string desc
+ * 15 iProduct 1 0x02 Index of prod string desc
+ * 16 iSerialNumber 1 0x02 Index of serial nmr string desc
+ * 17 bNumConfigurations 1 0x01 Number of possible configurations
+ *
+ * Configuration Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x09 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type
+ * 2 wTotalLength 2 0x0020 Total length of data
+ * 4 bNumInterfaces 1 0x01 Number of interfaces supported
+ * 5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req
+ * 6 iConfiguration 1 0x02 Index of config string descriptor
+ * 7 bmAttributes 1 0x20 Config characteristics Remote Wakeup
+ * 8 MaxPower 1 0x1E Max power consumption
+ *
+ * Interface Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x09 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x04 INTERFACE Descriptor Type
+ * 2 bInterfaceNumber 1 0x00 Number of interface
+ * 3 bAlternateSetting 1 0x00 Value used to select alternate
+ * 4 bNumEndpoints 1 0x02 Number of endpoints
+ * 5 bInterfaceClass 1 0xFF Class Code
+ * 6 bInterfaceSubClass 1 0xFF Subclass Code
+ * 7 bInterfaceProtocol 1 0xFF Protocol Code
+ * 8 iInterface 1 0x02 Index of interface string description
+ *
+ * IN Endpoint Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x07 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+ * 2 bEndpointAddress 1 0x82 Address of endpoint
+ * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+ * 4 bNumEndpoints 2 0x0040 maximum packet size
+ * 5 bInterval 1 0x00 Interval for polling endpoint
+ *
+ * OUT Endpoint Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x07 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+ * 2 bEndpointAddress 1 0x02 Address of endpoint
+ * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+ * 4 bNumEndpoints 2 0x0040 maximum packet size
+ * 5 bInterval 1 0x00 Interval for polling endpoint
+ *
+ * DATA FORMAT
+ *
+ * IN Endpoint
+ *
+ * The device reserves the first two bytes of data on this endpoint to contain the current
+ * values of the modem and line status registers. In the absence of data, the device
+ * generates a message consisting of these two status bytes every 40 ms
+ *
+ * Byte 0: Modem Status
+ *
+ * Offset Description
+ * B0 Reserved - must be 1
+ * B1 Reserved - must be 0
+ * B2 Reserved - must be 0
+ * B3 Reserved - must be 0
+ * B4 Clear to Send (CTS)
+ * B5 Data Set Ready (DSR)
+ * B6 Ring Indicator (RI)
+ * B7 Receive Line Signal Detect (RLSD)
+ *
+ * Byte 1: Line Status
+ *
+ * Offset Description
+ * B0 Data Ready (DR)
+ * B1 Overrun Error (OE)
+ * B2 Parity Error (PE)
+ * B3 Framing Error (FE)
+ * B4 Break Interrupt (BI)
+ * B5 Transmitter Holding Register (THRE)
+ * B6 Transmitter Empty (TEMT)
+ * B7 Error in RCVR FIFO
+ *
+ * OUT Endpoint
+ *
+ * This device reserves the first bytes of data on this endpoint contain the length
+ * and port identifier of the message. For the FTDI USB Serial converter the port
+ * identifier is always 1.
+ *
+ * Byte 0: Line Status
+ *
+ * Offset Description
+ * B0 Reserved - must be 1
+ * B1 Reserved - must be 0
+ * B2..7 Length of message - (not including Byte 0)
+ *
+ */
- Device Descriptor
-
-Offset Field Size Value Description
-0 bLength 1 0x12 Size of descriptor in bytes
-1 bDescriptorType 1 0x01 DEVICE Descriptor Type
-2 bcdUSB 2 0x0110 USB Spec Release Number
-4 bDeviceClass 1 0x00 Class Code
-5 bDeviceSubClass 1 0x00 SubClass Code
-6 bDeviceProtocol 1 0x00 Protocol Code
-7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0
-8 idVendor 2 0x0403 Vendor ID
-10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID)
-12 bcdDevice 2 0x0001 Device release number
-14 iManufacturer 1 0x01 Index of man. string desc
-15 iProduct 1 0x02 Index of prod string desc
-16 iSerialNumber 1 0x02 Index of serial nmr string desc
-17 bNumConfigurations 1 0x01 Number of possible configurations
-
-Configuration Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x09 Size of descriptor in bytes
-1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type
-2 wTotalLength 2 0x0020 Total length of data
-4 bNumInterfaces 1 0x01 Number of interfaces supported
-5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req
-6 iConfiguration 1 0x02 Index of config string descriptor
-7 bmAttributes 1 0x20 Config characteristics Remote Wakeup
-8 MaxPower 1 0x1E Max power consumption
-
-Interface Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x09 Size of descriptor in bytes
-1 bDescriptorType 1 0x04 INTERFACE Descriptor Type
-2 bInterfaceNumber 1 0x00 Number of interface
-3 bAlternateSetting 1 0x00 Value used to select alternate
-4 bNumEndpoints 1 0x02 Number of endpoints
-5 bInterfaceClass 1 0xFF Class Code
-6 bInterfaceSubClass 1 0xFF Subclass Code
-7 bInterfaceProtocol 1 0xFF Protocol Code
-8 iInterface 1 0x02 Index of interface string description
-
-IN Endpoint Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x07 Size of descriptor in bytes
-1 bDescriptorType 1 0x05 ENDPOINT descriptor type
-2 bEndpointAddress 1 0x82 Address of endpoint
-3 bmAttributes 1 0x02 Endpoint attributes - Bulk
-4 bNumEndpoints 2 0x0040 maximum packet size
-5 bInterval 1 0x00 Interval for polling endpoint
-
-OUT Endpoint Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x07 Size of descriptor in bytes
-1 bDescriptorType 1 0x05 ENDPOINT descriptor type
-2 bEndpointAddress 1 0x02 Address of endpoint
-3 bmAttributes 1 0x02 Endpoint attributes - Bulk
-4 bNumEndpoints 2 0x0040 maximum packet size
-5 bInterval 1 0x00 Interval for polling endpoint
-
-DATA FORMAT
-
-IN Endpoint
-
-The device reserves the first two bytes of data on this endpoint to contain the current
-values of the modem and line status registers. In the absence of data, the device
-generates a message consisting of these two status bytes every 40 ms
-
-Byte 0: Modem Status
-
-Offset Description
-B0 Reserved - must be 1
-B1 Reserved - must be 0
-B2 Reserved - must be 0
-B3 Reserved - must be 0
-B4 Clear to Send (CTS)
-B5 Data Set Ready (DSR)
-B6 Ring Indicator (RI)
-B7 Receive Line Signal Detect (RLSD)
-
-Byte 1: Line Status
-
-Offset Description
-B0 Data Ready (DR)
-B1 Overrun Error (OE)
-B2 Parity Error (PE)
-B3 Framing Error (FE)
-B4 Break Interrupt (BI)
-B5 Transmitter Holding Register (THRE)
-B6 Transmitter Empty (TEMT)
-B7 Error in RCVR FIFO
-
-OUT Endpoint
-
-This device reserves the first bytes of data on this endpoint contain the length
-and port identifier of the message. For the FTDI USB Serial converter the port
-identifier is always 1.
-
-Byte 0: Line Status
-
-Offset Description
-B0 Reserved - must be 1
-B1 Reserved - must be 0
-B2..7 Length of message - (not including Byte 0)
-
-*/
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
new file mode 100644
index 000000000..9fb22e4a8
--- /dev/null
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -0,0 +1,717 @@
+/*
+ * USB Keyspan PDA Converter driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+
+#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>
+
+struct ezusb_hex_record {
+ __u16 address;
+ __u8 data_size;
+ __u8 data[16];
+};
+
+#include "keyspan_pda_fw.h"
+
+#include "usb-serial.h"
+
+#define KEYSPAN_VENDOR_ID 0x06cd
+#define KEYSPAN_PDA_FAKE_ID 0x0103
+#define KEYSPAN_PDA_ID 0x0104 /* no clue */
+
+/* function prototypes for a Keyspan PDA serial converter */
+static int keyspan_pda_open (struct usb_serial_port *port,
+ struct file *filp);
+static void keyspan_pda_close (struct usb_serial_port *port,
+ struct file *filp);
+static int keyspan_pda_startup (struct usb_serial *serial);
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
+static int keyspan_pda_write_room (struct usb_serial_port *port);
+static int keyspan_pda_write (struct usb_serial_port *port,
+ int from_user,
+ const unsigned char *buf,
+ int count);
+static void keyspan_pda_write_bulk_callback (struct urb *urb);
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
+static int keyspan_pda_ioctl (struct usb_serial_port *port,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg);
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
+ struct termios *old);
+static void keyspan_pda_break_ctl (struct usb_serial_port *port,
+ int break_state);
+static int keyspan_pda_fake_startup (struct usb_serial *serial);
+
+
+/* All of the device info needed for the Keyspan PDA serial converter */
+static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
+static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
+static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
+struct usb_serial_device_type keyspan_pda_fake_device = {
+ name: "Keyspan PDA - (prerenumeration)",
+ idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
+ idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: keyspan_pda_fake_startup
+};
+struct usb_serial_device_type keyspan_pda_device = {
+ name: "Keyspan PDA",
+ idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
+ idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 0,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: keyspan_pda_open,
+ close: keyspan_pda_close,
+ write: keyspan_pda_write,
+ write_room: keyspan_pda_write_room,
+ write_bulk_callback: keyspan_pda_write_bulk_callback,
+ chars_in_buffer: keyspan_pda_chars_in_buffer,
+ throttle: keyspan_pda_rx_throttle,
+ unthrottle: keyspan_pda_rx_unthrottle,
+ startup: keyspan_pda_startup,
+ ioctl: keyspan_pda_ioctl,
+ set_termios: keyspan_pda_set_termios,
+ break_ctl: keyspan_pda_break_ctl,
+};
+
+
+static void keyspan_pda_rx_interrupt (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+
+ /* the urb might have been killed. */
+ if (urb->status)
+ return;
+
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ /* see if the message is data or a status interrupt */
+ switch (data[0]) {
+ case 0:
+ /* rest of message is rx data */
+ if (urb->actual_length) {
+ tty = serial->port[0].tty;
+ for (i = 1; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+ break;
+ case 1:
+ /* status interrupt */
+ dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+ switch (data[1]) {
+ case 1: /* modemline change */
+ break;
+ case 2: /* tx unthrottle interrupt */
+ tty = serial->port[0].tty;
+ serial->tx_throttled = 0;
+ wake_up(&serial->write_wait); /* wake up writer */
+ wake_up(&tty->write_wait); /* them too */
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* INT urbs are automatically re-submitted */
+}
+
+
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
+{
+ /* stop receiving characters. We just turn off the URB request, and
+ let chars pile up in the device. If we're doing hardware
+ flowcontrol, the device will signal the other end when its buffer
+ fills up. If we're doing XON/XOFF, this would be a good time to
+ send an XOFF, although it might make sense to foist that off
+ upon the device too. */
+
+ dbg("keyspan_pda_rx_throttle port %d", port->number);
+ usb_unlink_urb(port->read_urb);
+}
+
+
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
+{
+ /* just restart the receive interrupt URB */
+ dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+ if (usb_submit_urb(port->read_urb))
+ dbg(" usb_submit_urb(read urb) failed");
+ return;
+}
+
+
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+{
+ int rc;
+ int bindex;
+
+ switch(baud) {
+ case 110: bindex = 0; break;
+ case 300: bindex = 1; break;
+ case 1200: bindex = 2; break;
+ case 2400: bindex = 3; break;
+ case 4800: bindex = 4; break;
+ case 9600: bindex = 5; break;
+ case 19200: bindex = 6; break;
+ case 38400: bindex = 7; break;
+ case 57600: bindex = 8; break;
+ case 115200: bindex = 9; break;
+ default: return -EINVAL;
+ }
+
+ /* rather than figure out how to sleep while waiting for this
+ to complete, I just use the "legacy" API. */
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 0, /* set baud */
+ USB_TYPE_VENDOR
+ | USB_RECIP_INTERFACE
+ | USB_DIR_OUT, /* type */
+ bindex, /* value */
+ 0, /* index */
+ NULL, /* &data */
+ 0, /* size */
+ 2*HZ); /* timeout */
+ return(rc);
+}
+
+
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
+{
+ struct usb_serial *serial = port->serial;
+ int value;
+ if (break_state == -1)
+ value = 1; /* start break */
+ else
+ value = 0; /* clear break */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 4, /* set break */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ value, 0, NULL, 0, 2*HZ);
+ /* there is something funky about this.. the TCSBRK that 'cu' performs
+ ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
+ seconds apart, but it feels like the break sent isn't as long as it
+ is on /dev/ttyS0 */
+}
+
+
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ /* cflag specifies lots of stuff: number of stop bits, parity, number
+ of data bits, baud. What can the device actually handle?:
+ CSTOPB (1 stop bit or 2)
+ PARENB (parity)
+ CSIZE (5bit .. 8bit)
+ There is minimal hw support for parity (a PSW bit seems to hold the
+ parity of whatever is in the accumulator). The UART either deals
+ with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+ 1 special, stop). So, with firmware changes, we could do:
+ 8N1: 10 bit
+ 8N2: 11 bit, extra bit always (mark?)
+ 8[EOMS]1: 11 bit, extra bit is parity
+ 7[EOMS]1: 10 bit, b0/b7 is parity
+ 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+
+ HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+ bit.
+
+ For now, just do baud. */
+
+ switch (cflag & CBAUD) {
+ /* we could support more values here, just need to calculate
+ the necessary divisors in the firmware. <asm/termbits.h>
+ has the Bnnn constants. */
+ case B110: keyspan_pda_setbaud(serial, 110); break;
+ case B300: keyspan_pda_setbaud(serial, 300); break;
+ case B1200: keyspan_pda_setbaud(serial, 1200); break;
+ case B2400: keyspan_pda_setbaud(serial, 2400); break;
+ case B4800: keyspan_pda_setbaud(serial, 4800); break;
+ case B9600: keyspan_pda_setbaud(serial, 9600); break;
+ case B19200: keyspan_pda_setbaud(serial, 19200); break;
+ case B38400: keyspan_pda_setbaud(serial, 38400); break;
+ case B57600: keyspan_pda_setbaud(serial, 57600); break;
+ case B115200: keyspan_pda_setbaud(serial, 115200); break;
+ default: dbg("can't handle requested baud rate"); break;
+ }
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled.
+ DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+ read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
+
+static int keyspan_pda_get_modem_info(struct usb_serial *serial,
+ unsigned char *value)
+{
+ int rc;
+ unsigned char data;
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 3, /* get pins */
+ USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+ 0, 0, &data, 1, 2*HZ);
+ if (rc > 0)
+ *value = data;
+ return rc;
+}
+
+
+static int keyspan_pda_set_modem_info(struct usb_serial *serial,
+ unsigned char value)
+{
+ int rc;
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 3, /* set pins */
+ USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
+ value, 0, NULL, 0, 2*HZ);
+ return rc;
+}
+
+
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ int rc;
+ unsigned int value;
+ unsigned char status, mask;
+
+ switch (cmd) {
+ case TIOCMGET: /* get modem pins state */
+ rc = keyspan_pda_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ value =
+ ((status & (1<<7)) ? TIOCM_DTR : 0) |
+ ((status & (1<<6)) ? TIOCM_CAR : 0) |
+ ((status & (1<<5)) ? TIOCM_RNG : 0) |
+ ((status & (1<<4)) ? TIOCM_DSR : 0) |
+ ((status & (1<<3)) ? TIOCM_CTS : 0) |
+ ((status & (1<<2)) ? TIOCM_RTS : 0);
+ if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case TIOCMSET: /* set a state as returned by MGET */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ status =
+ ((value & TIOCM_DTR) ? (1<<7) : 0) |
+ ((value & TIOCM_CAR) ? (1<<6) : 0) |
+ ((value & TIOCM_RNG) ? (1<<5) : 0) |
+ ((value & TIOCM_DSR) ? (1<<4) : 0) |
+ ((value & TIOCM_CTS) ? (1<<3) : 0) |
+ ((value & TIOCM_RTS) ? (1<<2) : 0);
+ rc = keyspan_pda_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMBIS: /* set bits in bitmask <arg> */
+ case TIOCMBIC: /* clear bits from bitmask <arg> */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ rc = keyspan_pda_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ mask =
+ ((value & TIOCM_RTS) ? (1<<2) : 0) |
+ ((value & TIOCM_DTR) ? (1<<7) : 0);
+ if (cmd == TIOCMBIS)
+ status |= mask;
+ else
+ status &= ~mask;
+ rc = keyspan_pda_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ return 0; /* TODO */
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ int request_unthrottle = 0;
+ int rc = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* guess how much room is left in the device's ring buffer, and if we
+ want to send more than that, check first, updating our notion of
+ what is left. If our write will result in no room left, ask the
+ device to give us an interrupt when the room available rises above
+ a threshold, and hold off all writers (eventually, those using
+ select() or poll() too) until we receive that unthrottle interrupt.
+ Block if we can't write anything at all, otherwise write as much as
+ we can. */
+
+ if (count == 0) {
+ dbg(" write request of 0 bytes");
+ return (0);
+ }
+
+ /* we might block because of:
+ the TX urb is in-flight (wait until it completes)
+ the device is full (wait until it says there is room)
+ */
+ while (port->write_urb->status == -EINPROGRESS) {
+ if (0 /* file->f_flags & O_NONBLOCK */) {
+ rc = -EAGAIN;
+ goto err;
+ }
+ interruptible_sleep_on(&serial->write_wait);
+ if (signal_pending(current)) {
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ }
+
+ /* at this point the URB is in our control, nobody else can submit it
+ again (the only sudden transition was the one from EINPROGRESS to
+ finished) */
+
+ /* the next potential block is that our TX process might be throttled.
+ The transition from throttled->not happens because of an Rx
+ interrupt, and the wake_up occurs during the same interrupt, so we
+ have to be careful to avoid a race that would cause us to sleep
+ forever. */
+
+ add_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (serial->tx_throttled) {
+ /* device can't accomodate any more characters. Sleep until it
+ can. Woken up by an Rx interrupt message, which clears
+ tx_throttled first. */
+ dbg(" tx_throttled, going to sleep");
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serial->write_wait, &wait);
+ dbg(" woke up because of signal");
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ schedule();
+ dbg(" woke up");
+ }
+ remove_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+ if (count > serial->tx_room) {
+ unsigned char room;
+ /* Looks like we might overrun the Tx buffer. Ask the device
+ how much room it really has */
+ rc = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value: 0 means "remaining room" */
+ 0, /* index */
+ &room,
+ 1,
+ 2*HZ);
+ if (rc < 0) {
+ dbg(" roomquery failed");
+ return rc; /* failed */
+ }
+ if (rc == 0) {
+ dbg(" roomquery returned 0 bytes");
+ return -EIO; /* device didn't return any data */
+ }
+ dbg(" roomquery says %d", room);
+ serial->tx_room = room;
+ if (count > serial->tx_room) {
+ /* we're about to completely fill the Tx buffer, so
+ we'll be throttled afterwards. */
+ count = serial->tx_room;
+ request_unthrottle = 1;
+ }
+ }
+ serial->tx_room -= count;
+
+ if (count) {
+ /* now transfer data */
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
+ }
+ else {
+ memcpy (port->write_urb->transfer_buffer, buf, count);
+ }
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ dbg(" usb_submit_urb(write bulk) failed");
+ }
+ else {
+ /* There wasn't any room left, so we are throttled until
+ the buffer empties a bit */
+ request_unthrottle = 1;
+ }
+
+ if (request_unthrottle) {
+ dbg(" request_unthrottle");
+ /* ask the device to tell us when the tx buffer becomes
+ sufficiently empty */
+ serial->tx_throttled = 1; /* block writers */
+ rc = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ 7, /* request_unthrottle */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_OUT,
+ 16, /* value: threshold */
+ 0, /* index */
+ NULL,
+ 0,
+ 2*HZ);
+ }
+
+ return (count);
+ err:
+ return (rc);
+}
+
+
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ wake_up_interruptible(&serial->write_wait);
+
+ tty = port->tty;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+}
+
+
+static int keyspan_pda_write_room (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+
+ /* used by n_tty.c for processing of tabs and such. Giving it our
+ conservative guess is probably good enough, but needs testing by
+ running a console through the device. */
+
+ return (serial->tx_room);
+}
+
+
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+
+ /* when throttled, return at least WAKEUP_CHARS to tell select() (via
+ n_tty.c:normal_poll() ) that we're not writeable. */
+ if (serial->tx_throttled)
+ return 256;
+ return 0;
+}
+
+
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned char room;
+ int rc;
+
+ if (port->active) {
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /* find out how much room is in the Tx ring */
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value */
+ 0, /* index */
+ &room,
+ 1,
+ 2*HZ);
+ if (rc < 0) {
+ dbg(" roomquery failed");
+ return rc; /* failed */
+ }
+ if (rc == 0) {
+ dbg(" roomquery returned 0 bytes");
+ return -EIO; /* device didn't return any data */
+ }
+ serial->tx_room = room;
+ serial->tx_throttled = room ? 0 : 1;
+
+ /* the normal serial device seems to always turn on DTR and RTS here,
+ so do the same */
+ if (port->tty->termios->c_cflag & CBAUD)
+ keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+ else
+ keyspan_pda_set_modem_info(serial, 0);
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg(" usb_submit_urb(read int) failed");
+
+ return (0);
+}
+
+
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ /* the normal serial device seems to always shut off DTR and RTS now */
+ if (port->tty->termios->c_cflag & HUPCL)
+ keyspan_pda_set_modem_info(serial, 0);
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+}
+
+
+/* download the firmware to a "fake" device (pre-renumeration) */
+static int keyspan_pda_fake_startup (struct usb_serial *serial)
+{
+ int response;
+ const struct ezusb_hex_record *record;
+
+ /* download the firmware here ... */
+ response = ezusb_set_reset(serial, 1);
+
+ record = &keyspan_pda_firmware[0];
+ while(record->address != 0xffff) {
+ response = ezusb_writememory(serial, record->address,
+ (unsigned char *)record->data,
+ record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for Keyspan PDA "
+ "firmware (%d %04X %p %d)",
+ response,
+ record->address, record->data, record->data_size);
+ break;
+ }
+ record++;
+ }
+ /* bring device out of reset. Renumeration will occur in a moment
+ and the new device will bind to the real driver */
+ response = ezusb_set_reset(serial, 0);
+
+ /* we want this device to fail to have a driver assigned to it. */
+ return (1);
+}
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int keyspan_pda_startup (struct usb_serial *serial)
+{
+ struct usb_endpoint_descriptor *intin;
+ intin = serial->port[0].interrupt_in_endpoint;
+
+ /* set up the receive interrupt urb */
+ FILL_INT_URB(serial->port[0].read_urb, serial->dev,
+ usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
+ serial->port[0].interrupt_in_buffer,
+ intin->wMaxPacketSize,
+ keyspan_pda_rx_interrupt,
+ serial,
+ intin->bInterval);
+
+ init_waitqueue_head(&serial->write_wait);
+
+ return (0);
+}
+
+#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+
+
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
deleted file mode 100644
index 021754994..000000000
--- a/drivers/usb/serial/usb-serial.c
+++ /dev/null
@@ -1,2593 +0,0 @@
-/*
- * USB Serial Converter driver
- *
- * (C) Copyright (C) 1999, 2000
- * Greg Kroah-Hartman (greg@kroah.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver was originally based on the ACM driver by Armin Fuerst (which was
- * based on a driver by Brad Keryan)
- *
- * See Documentation/usb/usb-serial.txt for more information on using this driver
- *
- * (03/19/2000) gkh
- * Fixed oops that could happen when device was removed while a program
- * was talking to the device.
- * Removed the static urbs and now all urbs are created and destroyed
- * dynamically.
- * Reworked the internal interface. Now everything is based on the
- * usb_serial_port structure instead of the larger usb_serial structure.
- * This fixes the bug that a multiport device could not have more than
- * one port open at one time.
- *
- * (03/17/2000) gkh
- * Added config option for debugging messages.
- * Added patch for keyspan pda from Brian Warner.
- *
- * (03/06/2000) gkh
- * Added the keyspan pda code from Brian Warner <warner@lothar.com>
- * Moved a bunch of the port specific stuff into its own structure. This
- * is in anticipation of the true multiport devices (there's a bug if you
- * try to access more than one port of any multiport device right now)
- *
- * (02/21/2000) gkh
- * Made it so that any serial devices only have to specify which functions
- * they want to overload from the generic function calls (great,
- * inheritance in C, in a driver, just what I wanted...)
- * Added support for set_termios and ioctl function calls. No drivers take
- * advantage of this yet.
- * Removed the #ifdef MODULE, now there is no module specific code.
- * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
- * to Miles Lott).
- * Small fix to get_free_serial.
- *
- * (02/14/2000) gkh
- * Removed the Belkin and Peracom functionality from the driver due to
- * the lack of support from the vendor, and me not wanting people to
- * accidenatly buy the device, expecting it to work with Linux.
- * Added read_bulk_callback and write_bulk_callback to the type structure
- * for the needs of the FTDI and WhiteHEAT driver.
- * Changed all reverences to FTDI to FTDI_SIO at the request of Bill
- * Ryder.
- * Changed the output urb size back to the max endpoint size to make
- * the ftdi_sio driver have it easier, and due to the fact that it didn't
- * really increase the speed any.
- *
- * (02/11/2000) gkh
- * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
- * patch from Miles Lott (milos@insync.net).
- * Fixed bug with not restoring the minor range that a device grabs, if
- * the startup function fails (thanks Miles for finding this).
- *
- * (02/05/2000) gkh
- * Added initial framework for the Keyspan PDA serial converter so that
- * Brian Warner has a place to put his code.
- * Made the ezusb specific functions generic enough that different
- * devices can use them (whiteheat and keyspan_pda both need them).
- * Split out a whole bunch of structure and other stuff to a seperate
- * usb-serial.h file.
- * Made the Visor connection messages a little more understandable, now
- * that Miles Lott (milos@insync.net) has gotten the Generic channel to
- * work. Also made them always show up in the log file.
- *
- * (01/25/2000) gkh
- * Added initial framework for FTDI serial converter so that Bill Ryder
- * has a place to put his code.
- * Added the vendor specific info from Handspring. Now we can print out
- * informational debug messages as well as understand what is happening.
- *
- * (01/23/2000) gkh
- * Fixed problem of crash when trying to open a port that didn't have a
- * device assigned to it. Made the minor node finding a little smarter,
- * now it looks to find a continous space for the new device.
- *
- * (01/21/2000) gkh
- * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
- * Fixed get_serial_by_minor which was all messed up for multi port
- * devices. Fixed multi port problem for generic devices. Now the number
- * of ports is determined by the number of bulk out endpoints for the
- * generic device.
- *
- * (01/19/2000) gkh
- * Removed lots of cruft that was around from the old (pre urb) driver
- * interface.
- * Made the serial_table dynamic. This should save lots of memory when
- * the number of minor nodes goes up to 256.
- * Added initial support for devices that have more than one port.
- * Added more debugging comments for the Visor, and added a needed
- * set_configuration call.
- *
- * (01/17/2000) gkh
- * Fixed the WhiteHEAT firmware (my processing tool had a bug)
- * and added new debug loader firmware for it.
- * Removed the put_char function as it isn't really needed.
- * Added visor startup commands as found by the Win98 dump.
- *
- * (01/13/2000) gkh
- * Fixed the vendor id for the generic driver to the one I meant it to be.
- *
- * (01/12/2000) gkh
- * Forget the version numbering...that's pretty useless...
- * Made the driver able to be compiled so that the user can select which
- * converter they want to use. This allows people who only want the Visor
- * support to not pay the memory size price of the WhiteHEAT.
- * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
- * grabbed the root hub. Not good.
- *
- * version 0.4.0 (01/10/2000) gkh
- * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
- * device. Added startup function to allow firmware to be downloaded to
- * a device if it needs to be.
- * Added firmware download logic to the WhiteHEAT device.
- * Started to add #defines to split up the different drivers for potential
- * configuration option.
- *
- * version 0.3.1 (12/30/99) gkh
- * Fixed problems with urb for bulk out.
- * Added initial support for multiple sets of endpoints. This enables
- * the Handspring Visor to be attached successfully. Only the first
- * bulk in / bulk out endpoint pair is being used right now.
- *
- * version 0.3.0 (12/27/99) gkh
- * Added initial support for the Handspring Visor based on a patch from
- * Miles Lott (milos@sneety.insync.net)
- * Cleaned up the code a bunch and converted over to using urbs only.
- *
- * version 0.2.3 (12/21/99) gkh
- * Added initial support for the Connect Tech WhiteHEAT converter.
- * Incremented the number of ports in expectation of getting the
- * WhiteHEAT to work properly (4 ports per connection).
- * Added notification on insertion and removal of what port the
- * device is/was connected to (and what kind of device it was).
- *
- * version 0.2.2 (12/16/99) gkh
- * Changed major number to the new allocated number. We're legal now!
- *
- * version 0.2.1 (12/14/99) gkh
- * Fixed bug that happens when device node is opened when there isn't a
- * device attached to it. Thanks to marek@webdesign.no for noticing this.
- *
- * version 0.2.0 (11/10/99) gkh
- * Split up internals to make it easier to add different types of serial
- * converters to the code.
- * Added a "generic" driver that gets it's vendor and product id
- * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
- * for the idea and sample code (from the usb scanner driver.)
- * Cleared up any licensing questions by releasing it under the GNU GPL.
- *
- * version 0.1.2 (10/25/99) gkh
- * Fixed bug in detecting device.
- *
- * version 0.1.1 (10/05/99) gkh
- * Changed the major number to not conflict with anything else.
- *
- * version 0.1 (09/28/99) gkh
- * Can recognize the two different devices and start up a read from
- * device when asked to. Writes also work. No control signals yet, this
- * all is vendor specific data (i.e. no spec), also no control for
- * different baud rates or other bit settings.
- * Currently we are using the same devid as the acm driver. This needs
- * to change.
- *
- */
-
-#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>
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-#include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */
-#endif
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-struct ezusb_hex_record {
- __u16 address;
- __u8 data_size;
- __u8 data[16];
-};
-#include "keyspan_pda_fw.h"
-#endif
-
-#include "usb-serial.h"
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/* local function prototypes */
-static int serial_open (struct tty_struct *tty, struct file * filp);
-static void serial_close (struct tty_struct *tty, struct file * filp);
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
-static int serial_write_room (struct tty_struct *tty);
-static int serial_chars_in_buffer (struct tty_struct *tty);
-static void serial_throttle (struct tty_struct * tty);
-static void serial_unthrottle (struct tty_struct * tty);
-static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
-static void serial_set_termios (struct tty_struct *tty, struct termios * old);
-
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
-
-static struct usb_driver usb_serial_driver = {
- name: "serial",
- probe: usb_serial_probe,
- disconnect: usb_serial_disconnect,
-};
-
-static int serial_refcount;
-static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
-static struct termios * serial_termios[SERIAL_TTY_MINORS];
-static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
-static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
-
-
-static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
-{
- if (!serial) {
- dbg("%s - serial == NULL", function);
- return -1;
- }
- if (serial->magic != USB_SERIAL_MAGIC) {
- dbg("%s - bad magic number for serial", function);
- return -1;
- }
- if (!serial->type) {
- dbg("%s - serial->type == NULL!", function);
- return -1;
- }
-
- return 0;
-}
-
-
-static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
-{
- if (!port) {
- dbg("%s - port == NULL", function);
- return -1;
- }
- if (port->magic != USB_SERIAL_PORT_MAGIC) {
- dbg("%s - bad magic number for port", function);
- return -1;
- }
- if (!port->serial) {
- dbg("%s - port->serial == NULL", function);
- return -1;
- }
- if (!port->tty) {
- dbg("%s - port->tty == NULL", function);
- return -1;
- }
-
- return 0;
-}
-
-
-static struct usb_serial *get_serial_by_minor (int minor)
-{
- return serial_table[minor];
-}
-
-
-static struct usb_serial *get_free_serial (int num_ports, int *minor)
-{
- struct usb_serial *serial = NULL;
- int i, j;
- int good_spot;
-
- dbg("get_free_serial %d", num_ports);
-
- *minor = 0;
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- if (serial_table[i])
- continue;
-
- good_spot = 1;
- for (j = 1; j <= num_ports-1; ++j)
- if (serial_table[i+j])
- good_spot = 0;
- if (good_spot == 0)
- continue;
-
- if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
- err("Out of memory");
- return NULL;
- }
- memset(serial, 0, sizeof(struct usb_serial));
- serial->magic = USB_SERIAL_MAGIC;
- serial_table[i] = serial;
- *minor = i;
- dbg("minor base = %d", *minor);
- for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
- serial_table[i] = serial;
- return serial;
- }
- return NULL;
-}
-
-
-static void return_serial (struct usb_serial *serial)
-{
- int i;
-
- dbg("return_serial");
-
- if (serial == NULL)
- return;
-
- for (i = 0; i < serial->num_ports; ++i) {
- serial_table[serial->minor + i] = NULL;
- }
-
- return;
-}
-
-
-#ifdef USES_EZUSB_FUNCTIONS
-/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
-#define CPUCS_REG 0x7F92
-
-static int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
-{
- int result;
- unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL);
-
-// dbg("ezusb_writememory %x, %d", address, length);
-
- if (!transfer_buffer) {
- err("ezusb_writememory: kmalloc(%d) failed.", length);
- return -ENOMEM;
- }
- memcpy (transfer_buffer, data, length);
- result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
- kfree (transfer_buffer);
- return result;
-}
-
-
-static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
-{
- int response;
- dbg("ezusb_set_reset: %d", reset_bit);
- response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
- if (response < 0) {
- err("ezusb_set_reset %d failed", reset_bit);
- }
- return response;
-}
-
-#endif /* USES_EZUSB_FUNCTIONS */
-
-
-/*****************************************************************************
- * Driver tty interface functions
- *****************************************************************************/
-static int serial_open (struct tty_struct *tty, struct file * filp)
-{
- struct usb_serial *serial;
- struct usb_serial_port *port;
- int portNumber;
-
- dbg("serial_open");
-
- /* initialize the pointer incase something fails */
- tty->driver_data = NULL;
-
- /* get the serial object associated with this tty pointer */
- serial = get_serial_by_minor (MINOR(tty->device));
-
- if (serial_paranoia_check (serial, "serial_open")) {
- return -ENODEV;
- }
-
- /* set up our port structure */
- portNumber = MINOR(tty->device) - serial->minor;
- port = &serial->port[portNumber];
- port->number = portNumber;
- port->serial = serial;
- port->magic = USB_SERIAL_PORT_MAGIC;
-
- /* make the tty driver remember our port object, and us it */
- tty->driver_data = port;
- port->tty = tty;
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->open) {
- return (serial->type->open(port, filp));
- } else {
- return (generic_open(port, filp));
- }
-}
-
-
-static void serial_close(struct tty_struct *tty, struct file * filp)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_close");
-
- if (port_paranoia_check (port, "serial_close")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_close")) {
- return;
- }
-
- dbg("serial_close port %d", port->number);
-
- if (!port->active) {
- dbg ("port not opened");
- return;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->close) {
- serial->type->close(port, filp);
- } else {
- generic_close(port, filp);
- }
-}
-
-
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
- return -ENODEV;
- }
-
- dbg("serial_write port %d, %d byte(s)", port->number, count);
-
- if (!port->active) {
- dbg ("port not opened");
- return -EINVAL;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->write) {
- return (serial->type->write(port, from_user, buf, count));
- } else {
- return (generic_write(port, from_user, buf, count));
- }
-}
-
-
-static int serial_write_room (struct tty_struct *tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write_room");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
- return -ENODEV;
- }
-
- dbg("serial_write_room port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return -EINVAL;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->write_room) {
- return (serial->type->write_room(port));
- } else {
- return (generic_write_room(port));
- }
-}
-
-
-static int serial_chars_in_buffer (struct tty_struct *tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_chars_in_buffer");
-
- if (port_paranoia_check (port, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- if (!port->active) {
- dbg ("port not open");
- return -EINVAL;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->chars_in_buffer) {
- return (serial->type->chars_in_buffer(port));
- } else {
- return (generic_chars_in_buffer(port));
- }
-}
-
-
-static void serial_throttle (struct tty_struct * tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_throttle");
-
- if (port_paranoia_check (port, "serial_throttle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_throttle")) {
- return;
- }
-
- dbg("serial_throttle port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return;
- }
-
- /* pass on to the driver specific version of this function */
- if (serial->type->throttle) {
- serial->type->throttle(port);
- }
-
- return;
-}
-
-
-static void serial_unthrottle (struct tty_struct * tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_unthrottle");
-
- if (port_paranoia_check (port, "serial_unthrottle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_unthrottle")) {
- return;
- }
-
- dbg("serial_unthrottle port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return;
- }
-
- /* pass on to the driver specific version of this function */
- if (serial->type->unthrottle) {
- serial->type->unthrottle(port);
- }
-
- return;
-}
-
-
-static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_ioctl");
-
- if (port_paranoia_check (port, "serial_ioctl")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_ioctl")) {
- return -ENODEV;
- }
-
- dbg("serial_ioctl port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return -ENODEV;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->ioctl) {
- return (serial->type->ioctl(port, file, cmd, arg));
- } else {
- return -ENOIOCTLCMD;
- }
-}
-
-
-static void serial_set_termios (struct tty_struct *tty, struct termios * old)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_set_termios");
-
- if (port_paranoia_check (port, "serial_set_termios")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_set_termios")) {
- return;
- }
-
- dbg("serial_set_termios port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return;
- }
-
- /* pass on to the driver specific version of this function if it is available */
- if (serial->type->set_termios) {
- serial->type->set_termios(port, old);
- }
-
- return;
-}
-
-
-static void serial_break (struct tty_struct *tty, int break_state)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_break");
-
- if (port_paranoia_check (port, "serial_break")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_break")) {
- return;
- }
-
- dbg("serial_break port %d", port->number);
-
- if (!port->active) {
- dbg ("port not open");
- return;
- }
-
- /* pass on to the driver specific version of this function if it is
- available */
- if (serial->type->break_ctl) {
- serial->type->break_ctl(port, break_state);
- }
-}
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/*****************************************************************************
- * Connect Tech's White Heat specific driver functions
- *****************************************************************************/
-static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
-{
- dbg("whiteheat_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
- port->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- /* Need to do device specific setup here (control lines, baud rate, etc.) */
- /* FIXME!!! */
-
- return (0);
-}
-
-
-static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
-{
- dbg("whiteheat_close port %d", port->number);
-
- /* Need to change the control lines here */
- /* FIXME */
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
-}
-
-
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
- unsigned int cflag = port->tty->termios->c_cflag;
-
- dbg("whiteheat_set_termios port %d", port->number);
-
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("nothing to change...");
- return;
- }
- }
-
- /* do the parsing of the cflag to see what to set the line to */
- /* FIXME!! */
-
- return;
-}
-
-static void whiteheat_throttle (struct usb_serial_port *port)
-{
- dbg("whiteheat_throttle port %d", port->number);
-
- /* Change the control signals */
- /* FIXME!!! */
-
- return;
-}
-
-
-static void whiteheat_unthrottle (struct usb_serial_port *port)
-{
- dbg("whiteheat_unthrottle port %d", port->number);
-
- /* Change the control signals */
- /* FIXME!!! */
-
- return;
-}
-
-
-/* steps to download the firmware to the WhiteHEAT device:
- - hold the reset (by writing to the reset bit of the CPUCS register)
- - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
- - release the reset (by writing to the CPUCS register)
- - download the WH.HEX file for all addresses greater than 0x1b3f using
- VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
- - hold the reset
- - download the WH.HEX file for all addresses less than 0x1b40 using
- VENDOR_REQUEST_ANCHOR_LOAD
- - release the reset
- - device renumerated itself and comes up as new device id with all
- firmware download completed.
-*/
-static int whiteheat_startup (struct usb_serial *serial)
-{
- int response;
- const struct whiteheat_hex_record *record;
-
- dbg("whiteheat_startup");
-
- response = ezusb_set_reset (serial, 1);
-
- record = &whiteheat_loader[0];
- while (record->address != 0xffff) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for loader (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 0);
-
- record = &whiteheat_firmware[0];
- while (record->address < 0x1b40) {
- ++record;
- }
- while (record->address != 0xffff) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for first firmware step (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 1);
-
- record = &whiteheat_firmware[0];
- while (record->address < 0x1b40) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for second firmware step (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 0);
-
- /* we want this device to fail to have a driver assigned to it. */
- return (1);
-}
-#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-/******************************************************************************
- * Handspring Visor specific driver functions
- ******************************************************************************/
-static int visor_open (struct usb_serial_port *port, struct file *filp)
-{
- dbg("visor_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
-
- port->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return (0);
-}
-
-
-static void visor_close (struct usb_serial_port *port, struct file * filp)
-{
- struct usb_serial *serial = port->serial;
- unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
-
- dbg("visor_close port %d", port->number);
-
- if (!transfer_buffer) {
- err("visor_close: kmalloc(%d) failed.", 0x12);
- } else {
- /* send a shutdown message to the device */
- usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- }
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
-}
-
-
-static void visor_throttle (struct usb_serial_port *port)
-{
- dbg("visor_throttle port %d", port->number);
-
- usb_unlink_urb (port->read_urb);
-
- return;
-}
-
-
-static void visor_unthrottle (struct usb_serial_port *port)
-{
- dbg("visor_unthrottle port %d", port->number);
-
- if (usb_unlink_urb (port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return;
-}
-
-
-static int visor_startup (struct usb_serial *serial)
-{
- int response;
- int i;
- unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
-
- if (!transfer_buffer) {
- err("visor_startup: kmalloc(%d) failed.", 256);
- return -ENOMEM;
- }
-
- dbg("visor_startup");
-
- dbg("visor_setup: Set config to 1");
- usb_set_configuration (serial->dev, 1);
-
- /* send a get connection info request */
- response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- if (response < 0) {
- err("visor_startup: error getting connection information");
- } else {
- struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
- char *string;
- info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
- for (i = 0; i < connection_info->num_ports; ++i) {
- switch (connection_info->connections[i].port_function_id) {
- case VISOR_FUNCTION_GENERIC:
- string = "Generic";
- break;
- case VISOR_FUNCTION_DEBUGGER:
- string = "Debugger";
- break;
- case VISOR_FUNCTION_HOTSYNC:
- string = "HotSync";
- break;
- case VISOR_FUNCTION_CONSOLE:
- string = "Console";
- break;
- case VISOR_FUNCTION_REMOTE_FILE_SYS:
- string = "Remote File System";
- break;
- default:
- string = "unknown";
- break;
- }
- info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
- }
- }
-
- /* ask for the number of bytes available, but ignore the response as it is broken */
- response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
- 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
- if (response < 0) {
- err("visor_startup: error getting bytes available request");
- }
-
- kfree (transfer_buffer);
-
- /* continue on with initialization */
- return (0);
-}
-
-
-#endif /* CONFIG_USB_SERIAL_VISOR*/
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/******************************************************************************
- * FTDI SIO Serial Converter specific driver functions
- ******************************************************************************/
-
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/* to talk to the device */
-
-#include "ftdi_sio.h"
-
-static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- char buf[1]; /* Needed for the usb_control_msg I think */
-
- dbg("ftdi_sio_open port %d", port->number);
-
- if (port->active) {
- dbg ("port already open");
- return -EINVAL;
- }
- port->active = 1;
-
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_SIO,
- 0, buf, 0, HZ * 5);
-
- /* FIXME - Should I really purge the buffers? */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_PURGE_RX,
- 0, buf, 0, HZ * 5);
-
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_PURGE_TX,
- 0, buf, 0, HZ * 5);
-
-
- /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */
- if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_BAUDRATE_REQUEST,
- FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
- ftdi_sio_b9600, 0,
- buf, 0, HZ * 5) < 0){
- dbg("Error from baudrate urb");
- return(-EINVAL);
- }
-
- if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
- FTDI_SIO_SET_DATA_REQUEST_TYPE,
- 8 | FTDI_SIO_SET_DATA_PARITY_NONE |
- FTDI_SIO_SET_DATA_STOP_BITS_1, 0,
- buf, 0, HZ * 5) < 0){
- dbg("Error from cs8/noparity/1 stopbit urb");
- return(-EINVAL);
- }
-
- /* Disable flow control */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
- FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("error from flowcontrol urb");
- return(-EINVAL);
- }
-
- /* Turn on RTS and DTR since we are not flow controlling*/
- /* FIXME - check for correct behaviour clocal vs non clocal */
- /* FIXME - might be able to do both simultaneously */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from DTR HIGH urb");
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from RTS HIGH urb");
- }
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return (0);
-}
-
-
-static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- char buf[1];
-
- dbg("ftdi_sio_close port %d", port->number);
-
- /* FIXME - might be able to do both simultaneously */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from DTR LOW urb");
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from RTS LOW urb");
- }
-
- /* FIXME Should I flush the device here? - not doing it for now */
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
-}
-
-
-
-/* The ftdi_sio requires the first byte to have:
- B0 1
- B1 0
- B2..7 length of message excluding byte 0
-*/
-static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
- const int data_offset = 1;
-
- dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
-
- if (count == 0) {
- dbg("write request of 0 bytes");
- return 0;
- }
-
- /* only do something if we have a bulk out endpoint */
- if (serial->num_bulk_out) {
- unsigned char *first_byte = port->write_urb->transfer_buffer;
-
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return 0;
- }
-
- count += data_offset;
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count == 0) {
- return 0;
- }
-
- /* Copy in the data to send */
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer + data_offset ,
- buf, count - data_offset );
- }
- else {
- memcpy(port->write_urb->transfer_buffer + data_offset,
- buf, count - data_offset );
- }
-
- /* Write the control byte at the front of the packet*/
- first_byte = port->write_urb->transfer_buffer;
- *first_byte = 1 | ((count-data_offset) << 2) ;
-
-#ifdef DEBUG
- dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
-
- if (count) {
- int i;
- printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
- for (i = 0; i < count; ++i) {
- printk ("0x%02x ", first_byte[i]);
- if (first_byte[i] > ' ' && first_byte[i] < '~') {
- printk("%c ", first_byte[i]);
- } else {
- printk(" ");
- }
- }
-
-
- printk ("\n");
- }
-
-#endif
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
-
- dbg("write returning: %d", count - data_offset);
- return (count - data_offset);
- }
-
- /* no bulk out, so return 0 bytes written */
- return 0;
-}
-
-
-static void ftdi_sio_read_bulk_callback (struct urb *urb)
-{ /* ftdi_sio_serial_buld_callback */
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
- const int data_offset = 2;
- int i;
-
- dbg("ftdi_sio_read_bulk_callback");
-
- if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
- return;
- }
-
- if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
- return;
- }
-
-#ifdef DEBUG
- if (urb->actual_length > 2) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("0x%.2x ", data[i]);
- if (data[i] > ' ' && data[i] < '~') {
- printk("%c ", data[i]);
- } else {
- printk(" ");
- }
- }
- printk ("\n");
- }
-#endif
-
-
- if (urb->actual_length > data_offset) {
- tty = port->tty;
- for (i = data_offset ; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
- }
-
- /* Continue trying to always read */
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
-} /* ftdi_sio_serial_read_bulk_callback */
-
-
-static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
- struct usb_serial *serial = port->serial;
- unsigned int cflag = port->tty->termios->c_cflag;
- __u16 urb_value; /* Will hold the new flags */
- char buf[1]; /* Perhaps I should dynamically alloc this? */
-
- dbg("ftdi_sio_set_termios port %d", port->number);
-
- /* FIXME - we should keep the old termios really */
- /* FIXME -For this cut I don't care if the line is really changing or
- not - so just do the change regardless */
-
- /* Set number of data bits, parity, stop bits */
-
- urb_value = 0;
- urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
- FTDI_SIO_SET_DATA_STOP_BITS_1);
- urb_value |= (cflag & PARENB ?
- (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
- FTDI_SIO_SET_DATA_PARITY_EVEN) :
- FTDI_SIO_SET_DATA_PARITY_NONE);
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS5: urb_value |= 5; dbg("Setting CS5"); break;
- case CS6: urb_value |= 6; dbg("Setting CS6"); break;
- case CS7: urb_value |= 7; dbg("Setting CS7"); break;
- case CS8: urb_value |= 8; dbg("Setting CS8"); break;
- default:
- dbg("CSIZE was set but not CS5-CS8");
- }
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
- FTDI_SIO_SET_DATA_REQUEST_TYPE,
- urb_value , 0,
- buf, 0, 100) < 0) {
- dbg("FAILED to set databits/stopbits/parity");
- }
-
- /* Now do the baudrate */
- /* FIXME - should drop lines on B0 */
- /* FIXME Should also handle CLOCAL here */
-
- switch(cflag & CBAUD){
- case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
- case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
- case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
- case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
- case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
- case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
- case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
- case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
- case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
- case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
- default: dbg("FTDI_SIO does not support the baudrate requested");
- /* FIXME - how to return an error for this? */ break;
- }
- /* Send the URB */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_BAUDRATE_REQUEST,
- FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
- urb_value, 0,
- buf, 0, 100) < 0) {
- dbg("urb failed to set baurdrate");
- }
- return;
-}
-
-
-/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
-static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
-{
- struct usb_serial *serial = port->serial;
- __u16 urb_value=0; /* Will hold the new flags */
- char buf[1];
- int ret, mask;
-
- dbg("ftdi_sio_ioctl port %d", port->number);
-
- /* Based on code from acm.c */
- switch (cmd) {
-
- case TIOCMGET:
- /* Request the status from the device */
- if ((ret = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
- FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, 0,
- buf, 1, HZ * 5)) < 0 ) {
- dbg("Get not get modem status of device");
- return(ret);
- }
-
- return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
- (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
- (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
- (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
- (unsigned long *) arg);
- break;
-
- case TIOCMSET:
- case TIOCMBIS:
- case TIOCMBIC:
- if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
-
- /* FIXME Need to remember if we have set DTR or RTS since we
- can't ask the device */
- /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */
- if (mask & TIOCM_DTR) {
- switch(cmd) {
- case TIOCMSET:
- urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW;
- break;
-
- case TIOCMBIS:
- /* Will leave RTS alone and set DTR */
- urb_value = FTDI_SIO_SET_DTR_HIGH;
- break;
-
- case TIOCMBIC:
- urb_value = FTDI_SIO_SET_DTR_LOW;
- break;
- }
- }
-
- if (mask & TIOCM_RTS) {
- switch(cmd) {
- case TIOCMSET:
- urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH;
- break;
-
- case TIOCMBIS:
- /* Will leave DTR and set RTS */
- urb_value = FTDI_SIO_SET_RTS_HIGH;
- break;
-
- case TIOCMBIC:
- /* Will unset RTS */
- urb_value = FTDI_SIO_SET_RTS_LOW;
- break;
- }
- }
-
-
- return(usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- urb_value , 0,
- buf, 0, HZ * 5));
- }
-
- return -ENOIOCTLCMD;
-}
-
-#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
-
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/*****************************************************************************
- * Keyspan PDA specific driver functions
- *****************************************************************************/
-
-static void keyspan_pda_rx_interrupt (struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
- int i;
-
- /* the urb might have been killed. */
- if (urb->status)
- return;
-
- if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
- return;
- }
-
- /* see if the message is data or a status interrupt */
- switch (data[0]) {
- case 0:
- /* rest of message is rx data */
- if (urb->actual_length) {
- tty = serial->port[0].tty;
- for (i = 1; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
- }
- break;
- case 1:
- /* status interrupt */
- dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
- switch (data[1]) {
- case 1: /* modemline change */
- break;
- case 2: /* tx unthrottle interrupt */
- tty = serial->port[0].tty;
- serial->tx_throttled = 0;
- wake_up(&serial->write_wait); /* wake up writer */
- wake_up(&tty->write_wait); /* them too */
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- /* INT urbs are automatically re-submitted */
-}
-
-
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
-{
- /* stop receiving characters. We just turn off the URB request, and
- let chars pile up in the device. If we're doing hardware
- flowcontrol, the device will signal the other end when its buffer
- fills up. If we're doing XON/XOFF, this would be a good time to
- send an XOFF, although it might make sense to foist that off
- upon the device too. */
-
- dbg("keyspan_pda_rx_throttle port %d", port->number);
- usb_unlink_urb(port->read_urb);
-}
-
-
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
-{
- /* just restart the receive interrupt URB */
- dbg("keyspan_pda_rx_unthrottle port %d", port->number);
- if (usb_submit_urb(port->read_urb))
- dbg(" usb_submit_urb(read urb) failed");
- return;
-}
-
-
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
-{
- int rc;
- int bindex;
-
- switch(baud) {
- case 110: bindex = 0; break;
- case 300: bindex = 1; break;
- case 1200: bindex = 2; break;
- case 2400: bindex = 3; break;
- case 4800: bindex = 4; break;
- case 9600: bindex = 5; break;
- case 19200: bindex = 6; break;
- case 38400: bindex = 7; break;
- case 57600: bindex = 8; break;
- case 115200: bindex = 9; break;
- default: return -EINVAL;
- }
-
- /* rather than figure out how to sleep while waiting for this
- to complete, I just use the "legacy" API. */
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 0, /* set baud */
- USB_TYPE_VENDOR
- | USB_RECIP_INTERFACE
- | USB_DIR_OUT, /* type */
- bindex, /* value */
- 0, /* index */
- NULL, /* &data */
- 0, /* size */
- 2*HZ); /* timeout */
- return(rc);
-}
-
-
-static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
-{
- struct usb_serial *serial = port->serial;
- int value;
- if (break_state == -1)
- value = 1; /* start break */
- else
- value = 0; /* clear break */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 4, /* set break */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
- /* there is something funky about this.. the TCSBRK that 'cu' performs
- ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
- seconds apart, but it feels like the break sent isn't as long as it
- is on /dev/ttyS0 */
-}
-
-
-static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
-{
- struct usb_serial *serial = port->serial;
- unsigned int cflag = port->tty->termios->c_cflag;
-
- /* cflag specifies lots of stuff: number of stop bits, parity, number
- of data bits, baud. What can the device actually handle?:
- CSTOPB (1 stop bit or 2)
- PARENB (parity)
- CSIZE (5bit .. 8bit)
- There is minimal hw support for parity (a PSW bit seems to hold the
- parity of whatever is in the accumulator). The UART either deals
- with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
- 1 special, stop). So, with firmware changes, we could do:
- 8N1: 10 bit
- 8N2: 11 bit, extra bit always (mark?)
- 8[EOMS]1: 11 bit, extra bit is parity
- 7[EOMS]1: 10 bit, b0/b7 is parity
- 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
-
- HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
- bit.
-
- For now, just do baud. */
-
- switch (cflag & CBAUD) {
- /* we could support more values here, just need to calculate
- the necessary divisors in the firmware. <asm/termbits.h>
- has the Bnnn constants. */
- case B110: keyspan_pda_setbaud(serial, 110); break;
- case B300: keyspan_pda_setbaud(serial, 300); break;
- case B1200: keyspan_pda_setbaud(serial, 1200); break;
- case B2400: keyspan_pda_setbaud(serial, 2400); break;
- case B4800: keyspan_pda_setbaud(serial, 4800); break;
- case B9600: keyspan_pda_setbaud(serial, 9600); break;
- case B19200: keyspan_pda_setbaud(serial, 19200); break;
- case B38400: keyspan_pda_setbaud(serial, 38400); break;
- case B57600: keyspan_pda_setbaud(serial, 57600); break;
- case B115200: keyspan_pda_setbaud(serial, 115200); break;
- default: dbg("can't handle requested baud rate"); break;
- }
-}
-
-
-/* modem control pins: DTR and RTS are outputs and can be controlled.
- DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
- read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
-
-static int keyspan_pda_get_modem_info(struct usb_serial *serial,
- unsigned char *value)
-{
- int rc;
- unsigned char data;
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 3, /* get pins */
- USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
- 0, 0, &data, 1, 2*HZ);
- if (rc > 0)
- *value = data;
- return rc;
-}
-
-
-static int keyspan_pda_set_modem_info(struct usb_serial *serial,
- unsigned char value)
-{
- int rc;
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 3, /* set pins */
- USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
- return rc;
-}
-
-
-static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial *serial = port->serial;
- int rc;
- unsigned int value;
- unsigned char status, mask;
-
- switch (cmd) {
- case TIOCMGET: /* get modem pins state */
- rc = keyspan_pda_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- value =
- ((status & (1<<7)) ? TIOCM_DTR : 0) |
- ((status & (1<<6)) ? TIOCM_CAR : 0) |
- ((status & (1<<5)) ? TIOCM_RNG : 0) |
- ((status & (1<<4)) ? TIOCM_DSR : 0) |
- ((status & (1<<3)) ? TIOCM_CTS : 0) |
- ((status & (1<<2)) ? TIOCM_RTS : 0);
- if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCMSET: /* set a state as returned by MGET */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- status =
- ((value & TIOCM_DTR) ? (1<<7) : 0) |
- ((value & TIOCM_CAR) ? (1<<6) : 0) |
- ((value & TIOCM_RNG) ? (1<<5) : 0) |
- ((value & TIOCM_DSR) ? (1<<4) : 0) |
- ((value & TIOCM_CTS) ? (1<<3) : 0) |
- ((value & TIOCM_RTS) ? (1<<2) : 0);
- rc = keyspan_pda_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
- case TIOCMBIS: /* set bits in bitmask <arg> */
- case TIOCMBIC: /* clear bits from bitmask <arg> */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- rc = keyspan_pda_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- mask =
- ((value & TIOCM_RTS) ? (1<<2) : 0) |
- ((value & TIOCM_DTR) ? (1<<7) : 0);
- if (cmd == TIOCMBIS)
- status |= mask;
- else
- status &= ~mask;
- rc = keyspan_pda_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
- case TIOCMIWAIT:
- /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
- /* TODO */
- case TIOCGICOUNT:
- /* return count of modemline transitions */
- return 0; /* TODO */
- }
-
- return -ENOIOCTLCMD;
-}
-
-static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
- int request_unthrottle = 0;
- int rc = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- /* guess how much room is left in the device's ring buffer, and if we
- want to send more than that, check first, updating our notion of
- what is left. If our write will result in no room left, ask the
- device to give us an interrupt when the room available rises above
- a threshold, and hold off all writers (eventually, those using
- select() or poll() too) until we receive that unthrottle interrupt.
- Block if we can't write anything at all, otherwise write as much as
- we can. */
-
- if (count == 0) {
- dbg(" write request of 0 bytes");
- return (0);
- }
-
- /* we might block because of:
- the TX urb is in-flight (wait until it completes)
- the device is full (wait until it says there is room)
- */
- while (port->write_urb->status == -EINPROGRESS) {
- if (0 /* file->f_flags & O_NONBLOCK */) {
- rc = -EAGAIN;
- goto err;
- }
- interruptible_sleep_on(&serial->write_wait);
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- goto err;
- }
- }
-
- /* at this point the URB is in our control, nobody else can submit it
- again (the only sudden transition was the one from EINPROGRESS to
- finished) */
-
- /* the next potential block is that our TX process might be throttled.
- The transition from throttled->not happens because of an Rx
- interrupt, and the wake_up occurs during the same interrupt, so we
- have to be careful to avoid a race that would cause us to sleep
- forever. */
-
- add_wait_queue(&serial->write_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (serial->tx_throttled) {
- /* device can't accomodate any more characters. Sleep until it
- can. Woken up by an Rx interrupt message, which clears
- tx_throttled first. */
- dbg(" tx_throttled, going to sleep");
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
- dbg(" woke up because of signal");
- rc = -ERESTARTSYS;
- goto err;
- }
- schedule();
- dbg(" woke up");
- }
- remove_wait_queue(&serial->write_wait, &wait);
- set_current_state(TASK_RUNNING);
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count > serial->tx_room) {
- unsigned char room;
- /* Looks like we might overrun the Tx buffer. Ask the device
- how much room it really has */
- rc = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value: 0 means "remaining room" */
- 0, /* index */
- &room,
- 1,
- 2*HZ);
- if (rc < 0) {
- dbg(" roomquery failed");
- return rc; /* failed */
- }
- if (rc == 0) {
- dbg(" roomquery returned 0 bytes");
- return -EIO; /* device didn't return any data */
- }
- dbg(" roomquery says %d", room);
- serial->tx_room = room;
- if (count > serial->tx_room) {
- /* we're about to completely fill the Tx buffer, so
- we'll be throttled afterwards. */
- count = serial->tx_room;
- request_unthrottle = 1;
- }
- }
- serial->tx_room -= count;
-
- if (count) {
- /* now transfer data */
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer, buf, count);
- }
- else {
- memcpy (port->write_urb->transfer_buffer, buf, count);
- }
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg(" usb_submit_urb(write bulk) failed");
- }
- else {
- /* There wasn't any room left, so we are throttled until
- the buffer empties a bit */
- request_unthrottle = 1;
- }
-
- if (request_unthrottle) {
- dbg(" request_unthrottle");
- /* ask the device to tell us when the tx buffer becomes
- sufficiently empty */
- serial->tx_throttled = 1; /* block writers */
- rc = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- 7, /* request_unthrottle */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_OUT,
- 16, /* value: threshold */
- 0, /* index */
- NULL,
- 0,
- 2*HZ);
- }
-
- return (count);
- err:
- return (rc);
-}
-
-
-static void keyspan_pda_write_bulk_callback (struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
-
- if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
- return;
- }
-
- wake_up_interruptible(&serial->write_wait);
-
- tty = port->tty;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- wake_up_interruptible(&tty->write_wait);
-}
-
-
-static int keyspan_pda_write_room (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
-
- /* used by n_tty.c for processing of tabs and such. Giving it our
- conservative guess is probably good enough, but needs testing by
- running a console through the device. */
-
- return (serial->tx_room);
-}
-
-
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
-
- /* when throttled, return at least WAKEUP_CHARS to tell select() (via
- n_tty.c:normal_poll() ) that we're not writeable. */
- if (serial->tx_throttled)
- return 256;
- return 0;
-}
-
-
-static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- unsigned char room;
- int rc;
-
- if (port->active) {
- return -EINVAL;
- }
- port->active = 1;
-
- /* find out how much room is in the Tx ring */
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value */
- 0, /* index */
- &room,
- 1,
- 2*HZ);
- if (rc < 0) {
- dbg(" roomquery failed");
- return rc; /* failed */
- }
- if (rc == 0) {
- dbg(" roomquery returned 0 bytes");
- return -EIO; /* device didn't return any data */
- }
- serial->tx_room = room;
- serial->tx_throttled = room ? 0 : 1;
-
- /* the normal serial device seems to always turn on DTR and RTS here,
- so do the same */
- if (port->tty->termios->c_cflag & CBAUD)
- keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
- else
- keyspan_pda_set_modem_info(serial, 0);
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg(" usb_submit_urb(read int) failed");
-
- return (0);
-}
-
-
-static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
-
- /* the normal serial device seems to always shut off DTR and RTS now */
- if (port->tty->termios->c_cflag & HUPCL)
- keyspan_pda_set_modem_info(serial, 0);
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
-}
-
-
-/* download the firmware to a "fake" device (pre-renumeration) */
-static int keyspan_pda_fake_startup (struct usb_serial *serial)
-{
- int response;
- const struct ezusb_hex_record *record;
-
- /* download the firmware here ... */
- response = ezusb_set_reset(serial, 1);
-
- record = &keyspan_pda_firmware[0];
- while(record->address != 0xffff) {
- response = ezusb_writememory(serial, record->address,
- (unsigned char *)record->data,
- record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for Keyspan PDA "
- "firmware (%d %04X %p %d)",
- response,
- record->address, record->data, record->data_size);
- break;
- }
- record++;
- }
- /* bring device out of reset. Renumeration will occur in a moment
- and the new device will bind to the real driver */
- response = ezusb_set_reset(serial, 0);
-
- /* we want this device to fail to have a driver assigned to it. */
- return (1);
-}
-
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
-static int keyspan_pda_startup (struct usb_serial *serial)
-{
- struct usb_endpoint_descriptor *intin;
- intin = serial->port[0].interrupt_in_endpoint;
-
- /* set up the receive interrupt urb */
- FILL_INT_URB(serial->port[0].read_urb, serial->dev,
- usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
- serial->port[0].interrupt_in_buffer,
- intin->wMaxPacketSize,
- keyspan_pda_rx_interrupt,
- serial,
- intin->bInterval);
-
- init_waitqueue_head(&serial->write_wait);
-
- return (0);
-}
-
-#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
-
-
-/*****************************************************************************
- * generic devices specific driver functions
- *****************************************************************************/
-static int generic_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
- port->active = 1;
-
- /* if we have a bulk interrupt, start reading from it */
- if (serial->num_bulk_in) {
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
- }
-
- return (0);
-}
-
-
-static void generic_close (struct usb_serial_port *port, struct file * filp)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_close port %d", port->number);
-
- /* shutdown any bulk reads that might be going on */
- if (serial->num_bulk_out) {
- usb_unlink_urb (port->write_urb);
- }
- if (serial->num_bulk_in) {
- usb_unlink_urb (port->read_urb);
- }
-
- port->active = 0;
-}
-
-
-static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_serial_write port %d", port->number);
-
- if (count == 0) {
- dbg("write request of 0 bytes");
- return (0);
- }
-
- /* only do something if we have a bulk out endpoint */
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return (0);
- }
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer, buf, count);
- }
- else {
- memcpy (port->write_urb->transfer_buffer, buf, count);
- }
-
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
-
- return (count);
- }
-
- /* no bulk out, so return 0 bytes written */
- return (0);
-}
-
-
-static int generic_write_room (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
- int room;
-
- dbg("generic_write_room port %d", port->number);
-
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
- room = 0;
- else
- room = port->bulk_out_size;
- dbg("generic_write_room returns %d", room);
- return (room);
- }
-
- return (0);
-}
-
-
-static int generic_chars_in_buffer (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_chars_in_buffer port %d", port->number);
-
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- return (port->bulk_out_size);
- }
- }
-
- return (0);
-}
-
-
-static void generic_read_bulk_callback (struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
- int i;
-
- dbg("generic_read_bulk_callback");
-
- if (port_paranoia_check (port, "generic_read_bulk_callback")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
- return;
- }
-
- if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
- return;
- }
-
-#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("%.2x ", data[i]);
- }
- printk ("\n");
- }
-#endif
-
- 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);
- }
-
- /* Continue trying to always read */
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
-}
-
-
-static void generic_write_bulk_callback (struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
- struct tty_struct *tty;
-
- dbg("generic_write_bulk_callback");
-
- if (port_paranoia_check (port, "generic_write_bulk_callback")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
- return;
- }
-
- if (urb->status) {
- dbg("nonzero write bulk status received: %d", urb->status);
- return;
- }
-
- tty = port->tty;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- wake_up_interruptible(&tty->write_wait);
-
- return;
-}
-
-
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_serial *serial = NULL;
- struct usb_serial_port *port;
- struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
- struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
- struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
- struct usb_serial_device_type *type;
- int device_num;
- int minor;
- int buffer_size;
- int i;
- char interrupt_pipe;
- char bulk_in_pipe;
- char bulk_out_pipe;
- int num_interrupt_in = 0;
- int num_bulk_in = 0;
- int num_bulk_out = 0;
- int num_ports;
-
- /* loop through our list of known serial converters, and see if this device matches */
- device_num = 0;
- while (usb_serial_devices[device_num] != NULL) {
- type = usb_serial_devices[device_num];
- dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
-
- /* look at the device descriptor */
- if ((dev->descriptor.idVendor == *(type->idVendor)) &&
- (dev->descriptor.idProduct == *(type->idProduct))) {
-
- dbg("descriptor matches...looking at the endpoints");
-
- /* descriptor matches, let's try to find the endpoints needed */
- interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
-
- /* check out the endpoints */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- for (i = 0; i < interface->bNumEndpoints; ++i) {
- endpoint = &interface->endpoint[i];
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in");
- bulk_in_pipe = HAS;
- bulk_in_endpoint[num_bulk_in] = endpoint;
- ++num_bulk_in;
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out");
- bulk_out_pipe = HAS;
- bulk_out_endpoint[num_bulk_out] = endpoint;
- ++num_bulk_out;
- }
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
- /* we found a interrupt in endpoint */
- dbg("found interrupt in");
- interrupt_pipe = HAS;
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
- ++num_interrupt_in;
- }
-
- }
-
- /* verify that we found all of the endpoints that we need */
- if ((interrupt_pipe & type->needs_interrupt_in) &&
- (bulk_in_pipe & type->needs_bulk_in) &&
- (bulk_out_pipe & type->needs_bulk_out)) {
- /* found all that we need */
- info("%s converter detected", type->name);
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
- if (type == &generic_device)
- num_ports = num_bulk_out;
- else
-#endif
- num_ports = type->num_ports;
-
- serial = get_free_serial (num_ports, &minor);
- if (serial == NULL) {
- err("No more free serial devices");
- return NULL;
- }
-
- serial->dev = dev;
- serial->type = type;
- serial->minor = minor;
- serial->num_ports = num_ports;
- serial->num_bulk_in = num_bulk_in;
- serial->num_bulk_out = num_bulk_out;
- serial->num_interrupt_in = num_interrupt_in;
-
- /* collect interrupt_in endpoints now, because
- the keyspan_pda startup function needs
- to know about them */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- port->interrupt_in_endpoint = interrupt_in_endpoint[i];
- }
-
- /* if this device type has a startup function, call it */
- if (type->startup) {
- if (type->startup (serial)) {
- return_serial (serial);
- return NULL;
- }
- }
-
- /* set up the endpoint information */
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- port->read_urb = usb_alloc_urb (0);
- if (!port->read_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
- port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->bulk_in_buffer) {
- err("Couldn't allocate bulk_in_buffer");
- goto probe_error;
- }
- if (serial->type->read_bulk_callback) {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
- }
- }
-
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- port->write_urb = usb_alloc_urb(0);
- if (!port->write_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
- port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
- if (!port->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- goto probe_error;
- }
- if (serial->type->write_bulk_callback) {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
- }
- }
-
-#if 0 /* use this code when WhiteHEAT is up and running */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- port->control_urb = usb_alloc_urb(0);
- if (!port->control_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
- port->interrupt_in_buffer, buffer_size, serial_control_irq,
- port, interrupt_in_endpoint[i]->bInterval);
- }
-#endif
-
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
- }
-
- MOD_INC_USE_COUNT;
-
- return serial;
- } else {
- info("descriptors matched, but endpoints did not");
- }
- }
-
- /* look at the next type in our list */
- ++device_num;
- }
-
-probe_error:
- if (serial) {
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- if (port->read_urb)
- usb_free_urb (port->read_urb);
- if (serial->port[i].bulk_in_buffer[i])
- kfree (serial->port[i].bulk_in_buffer);
- }
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- if (port->write_urb)
- usb_free_urb (port->write_urb);
- if (serial->port[i].bulk_out_buffer)
- kfree (serial->port[i].bulk_out_buffer);
- }
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- if (port->control_urb)
- usb_free_urb (port->control_urb);
- if (serial->port[i].interrupt_in_buffer)
- kfree (serial->port[i].interrupt_in_buffer);
- }
-
- /* return the minor range that this device had */
- return_serial (serial);
-
- /* free up any memory that we allocated */
- kfree (serial);
- }
- return NULL;
-}
-
-
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_serial *serial = (struct usb_serial *) ptr;
- struct usb_serial_port *port;
- int i;
-
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i)
- serial->port[i].active = 0;
-
- for (i = 0; i < serial->num_bulk_in; ++i) {
- port = &serial->port[i];
- if (port->read_urb) {
- usb_unlink_urb (port->read_urb);
- usb_free_urb (port->read_urb);
- }
- if (port->bulk_in_buffer)
- kfree (port->bulk_in_buffer);
- }
- for (i = 0; i < serial->num_bulk_out; ++i) {
- port = &serial->port[i];
- if (port->write_urb) {
- usb_unlink_urb (port->write_urb);
- usb_free_urb (port->write_urb);
- }
- if (port->bulk_out_buffer)
- kfree (port->bulk_out_buffer);
- }
- for (i = 0; i < serial->num_interrupt_in; ++i) {
- port = &serial->port[i];
- if (port->control_urb) {
- usb_unlink_urb (port->control_urb);
- usb_free_urb (port->control_urb);
- }
- if (port->interrupt_in_buffer)
- kfree (port->interrupt_in_buffer);
- }
-
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
- }
-
- /* return the minor range that this device had */
- return_serial (serial);
-
- /* free up any memory that we allocated */
- kfree (serial);
-
- } else {
- info("device disconnected");
- }
-
- MOD_DEC_USE_COUNT;
-}
-
-
-static struct tty_driver serial_tty_driver = {
- magic: TTY_DRIVER_MAGIC,
- driver_name: "usb",
- name: "ttyUSB%d",
- major: SERIAL_TTY_MAJOR,
- minor_start: 0,
- num: SERIAL_TTY_MINORS,
- type: TTY_DRIVER_TYPE_SERIAL,
- subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW,
- refcount: &serial_refcount,
- table: serial_tty,
- proc_entry: NULL,
- other: NULL,
- termios: serial_termios,
- termios_locked: serial_termios_locked,
-
- open: serial_open,
- close: serial_close,
- write: serial_write,
- put_char: NULL,
- flush_chars: NULL,
- write_room: serial_write_room,
- ioctl: serial_ioctl,
- set_termios: serial_set_termios,
- set_ldisc: NULL,
- throttle: serial_throttle,
- unthrottle: serial_unthrottle,
- stop: NULL,
- start: NULL,
- hangup: NULL,
- break_ctl: serial_break,
- wait_until_sent: NULL,
- send_xchar: NULL,
- read_proc: NULL,
- chars_in_buffer: serial_chars_in_buffer,
- flush_buffer: NULL
-};
-
-
-int usb_serial_init(void)
-{
- int i;
-
- /* Initalize our global data */
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- serial_table[i] = NULL;
- }
-
- /* register the tty driver */
- serial_tty_driver.init_termios = tty_std_termios;
- serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- if (tty_register_driver (&serial_tty_driver)) {
- err("failed to register tty driver");
- return -EPERM;
- }
-
- /* register the USB driver */
- if (usb_register(&usb_serial_driver) < 0) {
- tty_unregister_driver(&serial_tty_driver);
- return -1;
- }
-
- info("support registered");
- return 0;
-}
-
-
-void usb_serial_exit(void)
-{
- tty_unregister_driver(&serial_tty_driver);
- usb_deregister(&usb_serial_driver);
-}
-
-
-module_init(usb_serial_init);
-module_exit(usb_serial_exit);
-
-
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 48082101a..6211a6309 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -19,47 +19,22 @@
#include <linux/config.h>
-/* Module information */
-MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
-MODULE_DESCRIPTION("USB Serial Driver");
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-static __u16 vendor = 0x05f9;
-static __u16 product = 0xffff;
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-#endif
-
-
-/* USB Serial devices vendor ids and device ids that this driver supports */
-#define CONNECT_TECH_VENDOR_ID 0x0710
-#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
-#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
-#define HANDSPRING_VENDOR_ID 0x082d
-#define HANDSPRING_VISOR_ID 0x0100
-#define FTDI_VENDOR_ID 0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
-#define KEYSPAN_VENDOR_ID 0x06cd
-#define KEYSPAN_PDA_FAKE_ID 0x0103
-#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-
#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */
-
-#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
#define USB_SERIAL_MAGIC 0x6702 /* magic number for usb_serial struct */
#define USB_SERIAL_PORT_MAGIC 0x7301 /* magic number for usb_serial_port struct */
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
struct usb_serial_port {
int magic;
struct usb_serial *serial; /* pointer back to the owner of this port */
- struct tty_struct * tty; /* the coresponding tty for this device */
+ struct tty_struct * tty; /* the coresponding tty for this port */
unsigned char minor;
unsigned char number;
char active; /* someone has this device open */
@@ -81,8 +56,9 @@ struct usb_serial_port {
struct usb_serial {
int magic;
struct usb_device * dev;
- struct usb_serial_device_type * type;
- unsigned char minor;
+ struct usb_serial_device_type * type; /* the type of usb serial device this is */
+ struct tty_driver * tty_driver; /* the tty_driver for this device */
+ unsigned char minor; /* the starting minor number for this device */
unsigned char num_ports; /* the number of ports this device has */
char num_interrupt_in; /* number of interrupt in endpoints we have */
char num_bulk_in; /* number of bulk in endpoints we have */
@@ -141,299 +117,67 @@ struct usb_serial_device_type {
};
-/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
-/* need to always compile these in, as some of the other devices use these functions as their own. */
-/* if a driver does not provide a function pointer, the generic function will be called. */
-static int generic_open (struct usb_serial_port *port, struct file *filp);
-static void generic_close (struct usb_serial_port *port, struct file *filp);
-static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static int generic_write_room (struct usb_serial_port *port);
-static int generic_chars_in_buffer (struct usb_serial_port *port);
-static void generic_read_bulk_callback (struct urb *urb);
-static void generic_write_bulk_callback (struct urb *urb);
-
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-/* All of the device info needed for the Generic Serial Converter */
-static struct usb_serial_device_type generic_device = {
- name: "Generic",
- idVendor: &vendor, /* use the user specified vendor id */
- idProduct: &product, /* use the user specified product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/* function prototypes for the Connect Tech WhiteHEAT serial converter */
-static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
-static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
-static void whiteheat_throttle (struct usb_serial_port *port);
-static void whiteheat_unthrottle (struct usb_serial_port *port);
-static int whiteheat_startup (struct usb_serial *serial);
-
-/* All of the device info needed for the Connect Tech WhiteHEAT */
-static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
-static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID;
-static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID;
-static struct usb_serial_device_type whiteheat_fake_device = {
- name: "Connect Tech - WhiteHEAT - (prerenumeration)",
- idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
- idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: whiteheat_startup
-};
-static struct usb_serial_device_type whiteheat_device = {
- name: "Connect Tech - WhiteHEAT",
- idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
- idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 4,
- open: whiteheat_open,
- close: whiteheat_close,
- throttle: whiteheat_throttle,
- unthrottle: whiteheat_unthrottle,
- set_termios: whiteheat_set_termios,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-
-/****************************************************************************
- * Handspring Visor Vendor specific request codes (bRequest values)
- * A big thank you to Handspring for providing the following information.
- * If anyone wants the original file where these values and structures came
- * from, send email to <greg@kroah.com>.
- ****************************************************************************/
-
-/****************************************************************************
- * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
- * are available to be transfered to the host for the specified endpoint.
- * Currently this is not used, and always returns 0x0001
- ****************************************************************************/
-#define VISOR_REQUEST_BYTES_AVAILABLE 0x01
-
-/****************************************************************************
- * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
- * is now closing the pipe. An empty packet is sent in response.
- ****************************************************************************/
-#define VISOR_CLOSE_NOTIFICATION 0x02
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
- * get the endpoints used by the connection.
- ****************************************************************************/
-#define VISOR_GET_CONNECTION_INFORMATION 0x03
-
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
- ****************************************************************************/
-struct visor_connection_info {
- __u16 num_ports;
- struct {
- __u8 port_function_id;
- __u8 port;
- } connections[2];
-};
-
-/* struct visor_connection_info.connection[x].port defines: */
-#define VISOR_ENDPOINT_1 0x01
-#define VISOR_ENDPOINT_2 0x02
-
-/* struct visor_connection_info.connection[x].port_function_id defines: */
-#define VISOR_FUNCTION_GENERIC 0x00
-#define VISOR_FUNCTION_DEBUGGER 0x01
-#define VISOR_FUNCTION_HOTSYNC 0x02
-#define VISOR_FUNCTION_CONSOLE 0x03
-#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04
-
-
-/* function prototypes for a handspring visor */
-static int visor_open (struct usb_serial_port *port, struct file *filp);
-static void visor_close (struct usb_serial_port *port, struct file *filp);
-static void visor_throttle (struct usb_serial_port *port);
-static void visor_unthrottle (struct usb_serial_port *port);
-static int visor_startup (struct usb_serial *serial);
-
-/* All of the device info needed for the Handspring Visor */
-static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
-static __u16 handspring_product_id = HANDSPRING_VISOR_ID;
-static struct usb_serial_device_type handspring_device = {
- name: "Handspring Visor",
- idVendor: &handspring_vendor_id, /* the Handspring vendor ID */
- idProduct: &handspring_product_id, /* the Handspring Visor product id */
- needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_interrupt_in: 0,
- num_bulk_in: 2,
- num_bulk_out: 2,
- num_ports: 2,
- open: visor_open,
- close: visor_close,
- throttle: visor_throttle,
- unthrottle: visor_unthrottle,
- startup: visor_startup,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/* function prototypes for a FTDI serial converter */
-static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp);
-static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp);
-static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static void ftdi_sio_read_bulk_callback (struct urb *urb);
-static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old);
-static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-
-/* All of the device info needed for the FTDI SIO serial converter */
-static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
-static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type ftdi_sio_device = {
- name: "FTDI SIO",
- idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */
- idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */
- needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: ftdi_sio_open,
- close: ftdi_sio_close,
- write: ftdi_sio_write,
- ioctl: ftdi_sio_ioctl,
- read_bulk_callback: ftdi_sio_read_bulk_callback,
- set_termios: ftdi_sio_set_termios
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_open (struct usb_serial_port *port,
- struct file *filp);
-static void keyspan_pda_close (struct usb_serial_port *port,
- struct file *filp);
-static int keyspan_pda_startup (struct usb_serial *serial);
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
-static int keyspan_pda_write_room (struct usb_serial_port *port);
-static int keyspan_pda_write (struct usb_serial_port *port,
- int from_user,
- const unsigned char *buf,
- int count);
-static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
-static int keyspan_pda_ioctl (struct usb_serial_port *port,
- struct file *file,
- unsigned int cmd,
- unsigned long arg);
-static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old);
-static void keyspan_pda_break_ctl (struct usb_serial_port *port,
- int break_state);
-static int keyspan_pda_fake_startup (struct usb_serial *serial);
-
-/* All of the device info needed for the Keyspan PDA serial converter */
-static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
-static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
-static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
-static struct usb_serial_device_type keyspan_pda_fake_device = {
- name: "Keyspan PDA - (prerenumeration)",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_pda_fake_startup
-};
-static struct usb_serial_device_type keyspan_pda_device = {
- name: "Keyspan PDA",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
- needs_interrupt_in: MUST_HAVE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: 1,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- open: keyspan_pda_open,
- close: keyspan_pda_close,
- write: keyspan_pda_write,
- write_room: keyspan_pda_write_room,
- write_bulk_callback: keyspan_pda_write_bulk_callback,
- chars_in_buffer: keyspan_pda_chars_in_buffer,
- throttle: keyspan_pda_rx_throttle,
- unthrottle: keyspan_pda_rx_unthrottle,
- startup: keyspan_pda_startup,
- ioctl: keyspan_pda_ioctl,
- set_termios: keyspan_pda_set_termios,
- break_ctl: keyspan_pda_break_ctl,
-};
-#endif
-
-
-/* To add support for another serial converter, create a usb_serial_device_type
- structure for that device, and add it to this list, making sure that the
- last entry is NULL. */
-static struct usb_serial_device_type *usb_serial_devices[] = {
-#ifdef CONFIG_USB_SERIAL_GENERIC
- &generic_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
- &whiteheat_fake_device,
- &whiteheat_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_VISOR
- &handspring_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
- &ftdi_sio_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
- &keyspan_pda_fake_device,
- &keyspan_pda_device,
-#endif
- NULL
-};
+extern struct usb_serial_device_type handspring_device;
+extern struct usb_serial_device_type whiteheat_fake_device;
+extern struct usb_serial_device_type whiteheat_device;
+extern struct usb_serial_device_type ftdi_sio_device;
+extern struct usb_serial_device_type keyspan_pda_fake_device;
+extern struct usb_serial_device_type keyspan_pda_device;
/* determine if we should include the EzUSB loader functions */
#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_WHITEHEAT)
#define USES_EZUSB_FUNCTIONS
+ extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
#else
#undef USES_EZUSB_FUNCTIONS
#endif
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
+{
+ if (!serial) {
+ dbg("%s - serial == NULL", function);
+ return -1;
+ }
+ if (serial->magic != USB_SERIAL_MAGIC) {
+ dbg("%s - bad magic number for serial", function);
+ return -1;
+ }
+ if (!serial->type) {
+ dbg("%s - serial->type == NULL!", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
+{
+ if (!port) {
+ dbg("%s - port == NULL", function);
+ return -1;
+ }
+ if (port->magic != USB_SERIAL_PORT_MAGIC) {
+ dbg("%s - bad magic number for port", function);
+ return -1;
+ }
+ if (!port->serial) {
+ dbg("%s - port->serial == NULL", function);
+ return -1;
+ }
+ if (!port->tty) {
+ dbg("%s - port->tty == NULL", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+
#endif /* ifdef __LINUX_USB_SERIAL_H */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
new file mode 100644
index 000000000..0c1972675
--- /dev/null
+++ b/drivers/usb/serial/usbserial.c
@@ -0,0 +1,1323 @@
+/*
+ * USB Serial Converter driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was
+ * based on a driver by Brad Keryan)
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (04/03/2000) gkh
+ * Changed the probe process to remove the module unload races.
+ * Changed where the tty layer gets initialized to have devfs work nicer.
+ * Added initial devfs support.
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ * (03/19/2000) gkh
+ * Fixed oops that could happen when device was removed while a program
+ * was talking to the device.
+ * Removed the static urbs and now all urbs are created and destroyed
+ * dynamically.
+ * Reworked the internal interface. Now everything is based on the
+ * usb_serial_port structure instead of the larger usb_serial structure.
+ * This fixes the bug that a multiport device could not have more than
+ * one port open at one time.
+ *
+ * (03/17/2000) gkh
+ * Added config option for debugging messages.
+ * Added patch for keyspan pda from Brian Warner.
+ *
+ * (03/06/2000) gkh
+ * Added the keyspan pda code from Brian Warner <warner@lothar.com>
+ * Moved a bunch of the port specific stuff into its own structure. This
+ * is in anticipation of the true multiport devices (there's a bug if you
+ * try to access more than one port of any multiport device right now)
+ *
+ * (02/21/2000) gkh
+ * Made it so that any serial devices only have to specify which functions
+ * they want to overload from the generic function calls (great,
+ * inheritance in C, in a driver, just what I wanted...)
+ * Added support for set_termios and ioctl function calls. No drivers take
+ * advantage of this yet.
+ * Removed the #ifdef MODULE, now there is no module specific code.
+ * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ * to Miles Lott).
+ * Small fix to get_free_serial.
+ *
+ * (02/14/2000) gkh
+ * Removed the Belkin and Peracom functionality from the driver due to
+ * the lack of support from the vendor, and me not wanting people to
+ * accidenatly buy the device, expecting it to work with Linux.
+ * Added read_bulk_callback and write_bulk_callback to the type structure
+ * for the needs of the FTDI and WhiteHEAT driver.
+ * Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+ * Ryder.
+ * Changed the output urb size back to the max endpoint size to make
+ * the ftdi_sio driver have it easier, and due to the fact that it didn't
+ * really increase the speed any.
+ *
+ * (02/11/2000) gkh
+ * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+ * patch from Miles Lott (milos@insync.net).
+ * Fixed bug with not restoring the minor range that a device grabs, if
+ * the startup function fails (thanks Miles for finding this).
+ *
+ * (02/05/2000) gkh
+ * Added initial framework for the Keyspan PDA serial converter so that
+ * Brian Warner has a place to put his code.
+ * Made the ezusb specific functions generic enough that different
+ * devices can use them (whiteheat and keyspan_pda both need them).
+ * Split out a whole bunch of structure and other stuff to a seperate
+ * usb-serial.h file.
+ * Made the Visor connection messages a little more understandable, now
+ * that Miles Lott (milos@insync.net) has gotten the Generic channel to
+ * work. Also made them always show up in the log file.
+ *
+ * (01/25/2000) gkh
+ * Added initial framework for FTDI serial converter so that Bill Ryder
+ * has a place to put his code.
+ * Added the vendor specific info from Handspring. Now we can print out
+ * informational debug messages as well as understand what is happening.
+ *
+ * (01/23/2000) gkh
+ * Fixed problem of crash when trying to open a port that didn't have a
+ * device assigned to it. Made the minor node finding a little smarter,
+ * now it looks to find a continous space for the new device.
+ *
+ * (01/21/2000) gkh
+ * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+ * Fixed get_serial_by_minor which was all messed up for multi port
+ * devices. Fixed multi port problem for generic devices. Now the number
+ * of ports is determined by the number of bulk out endpoints for the
+ * generic device.
+ *
+ * (01/19/2000) gkh
+ * Removed lots of cruft that was around from the old (pre urb) driver
+ * interface.
+ * Made the serial_table dynamic. This should save lots of memory when
+ * the number of minor nodes goes up to 256.
+ * Added initial support for devices that have more than one port.
+ * Added more debugging comments for the Visor, and added a needed
+ * set_configuration call.
+ *
+ * (01/17/2000) gkh
+ * Fixed the WhiteHEAT firmware (my processing tool had a bug)
+ * and added new debug loader firmware for it.
+ * Removed the put_char function as it isn't really needed.
+ * Added visor startup commands as found by the Win98 dump.
+ *
+ * (01/13/2000) gkh
+ * Fixed the vendor id for the generic driver to the one I meant it to be.
+ *
+ * (01/12/2000) gkh
+ * Forget the version numbering...that's pretty useless...
+ * Made the driver able to be compiled so that the user can select which
+ * converter they want to use. This allows people who only want the Visor
+ * support to not pay the memory size price of the WhiteHEAT.
+ * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+ * grabbed the root hub. Not good.
+ *
+ * version 0.4.0 (01/10/2000) gkh
+ * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+ * device. Added startup function to allow firmware to be downloaded to
+ * a device if it needs to be.
+ * Added firmware download logic to the WhiteHEAT device.
+ * Started to add #defines to split up the different drivers for potential
+ * configuration option.
+ *
+ * version 0.3.1 (12/30/99) gkh
+ * Fixed problems with urb for bulk out.
+ * Added initial support for multiple sets of endpoints. This enables
+ * the Handspring Visor to be attached successfully. Only the first
+ * bulk in / bulk out endpoint pair is being used right now.
+ *
+ * version 0.3.0 (12/27/99) gkh
+ * Added initial support for the Handspring Visor based on a patch from
+ * Miles Lott (milos@sneety.insync.net)
+ * Cleaned up the code a bunch and converted over to using urbs only.
+ *
+ * version 0.2.3 (12/21/99) gkh
+ * Added initial support for the Connect Tech WhiteHEAT converter.
+ * Incremented the number of ports in expectation of getting the
+ * WhiteHEAT to work properly (4 ports per connection).
+ * Added notification on insertion and removal of what port the
+ * device is/was connected to (and what kind of device it was).
+ *
+ * version 0.2.2 (12/16/99) gkh
+ * Changed major number to the new allocated number. We're legal now!
+ *
+ * version 0.2.1 (12/14/99) gkh
+ * Fixed bug that happens when device node is opened when there isn't a
+ * device attached to it. Thanks to marek@webdesign.no for noticing this.
+ *
+ * version 0.2.0 (11/10/99) gkh
+ * Split up internals to make it easier to add different types of serial
+ * converters to the code.
+ * Added a "generic" driver that gets it's vendor and product id
+ * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+ * for the idea and sample code (from the usb scanner driver.)
+ * Cleared up any licensing questions by releasing it under the GNU GPL.
+ *
+ * version 0.1.2 (10/25/99) gkh
+ * Fixed bug in detecting device.
+ *
+ * version 0.1.1 (10/05/99) gkh
+ * Changed the major number to not conflict with anything else.
+ *
+ * version 0.1 (09/28/99) gkh
+ * Can recognize the two different devices and start up a read from
+ * device when asked to. Writes also work. No control signals yet, this
+ * all is vendor specific data (i.e. no spec), also no control for
+ * different baud rates or other bit settings.
+ * Currently we are using the same devid as the acm driver. This needs
+ * to change.
+ *
+ */
+
+#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>
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_DESCRIPTION("USB Serial Driver");
+
+#include "usb-serial.h"
+
+
+/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
+/* need to always compile these in, as some of the other devices use these functions as their own. */
+/* if a driver does not provide a function pointer, the generic function will be called. */
+static int generic_open (struct usb_serial_port *port, struct file *filp);
+static void generic_close (struct usb_serial_port *port, struct file *filp);
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int generic_write_room (struct usb_serial_port *port);
+static int generic_chars_in_buffer (struct usb_serial_port *port);
+static void generic_read_bulk_callback (struct urb *urb);
+static void generic_write_bulk_callback (struct urb *urb);
+
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+static __u16 vendor = 0x05f9;
+static __u16 product = 0xffff;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+/* All of the device info needed for the Generic Serial Converter */
+static struct usb_serial_device_type generic_device = {
+ name: "Generic",
+ idVendor: &vendor, /* use the user specified vendor id */
+ idProduct: &product, /* use the user specified product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+};
+#endif
+
+
+/* To add support for another serial converter, create a usb_serial_device_type
+ structure for that device, and add it to this list, making sure that the
+ last entry is NULL. */
+static struct usb_serial_device_type *usb_serial_devices[] = {
+#ifdef CONFIG_USB_SERIAL_GENERIC
+ &generic_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+ &whiteheat_fake_device,
+ &whiteheat_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_VISOR
+ &handspring_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+ &ftdi_sio_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+ &keyspan_pda_fake_device,
+ &keyspan_pda_device,
+#endif
+ NULL
+};
+
+
+/* variables needed for the tty_driver structure */
+static char *driver_name = "usb";
+static char *tty_driver_name = "usb/tty/%d";
+
+
+/* local function prototypes */
+static int serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int serial_write_room (struct tty_struct *tty);
+static int serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver usb_serial_driver = {
+ name: "serial",
+ probe: usb_serial_probe,
+ disconnect: usb_serial_disconnect,
+};
+
+static int serial_refcount;
+static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
+static struct termios * serial_termios[SERIAL_TTY_MINORS];
+static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
+static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
+ return serial_table[minor];
+}
+
+
+static struct usb_serial *get_free_serial (int num_ports, int *minor)
+{
+ struct usb_serial *serial = NULL;
+ int i, j;
+ int good_spot;
+
+ dbg("get_free_serial %d", num_ports);
+
+ *minor = 0;
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ if (serial_table[i])
+ continue;
+
+ good_spot = 1;
+ for (j = 1; j <= num_ports-1; ++j)
+ if (serial_table[i+j])
+ good_spot = 0;
+ if (good_spot == 0)
+ continue;
+
+ if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
+ err("Out of memory");
+ return NULL;
+ }
+ memset(serial, 0, sizeof(struct usb_serial));
+ serial->magic = USB_SERIAL_MAGIC;
+ serial_table[i] = serial;
+ *minor = i;
+ dbg("minor base = %d", *minor);
+ for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
+ serial_table[i] = serial;
+ return serial;
+ }
+ return NULL;
+}
+
+
+static void return_serial (struct usb_serial *serial)
+{
+ int i;
+
+ dbg("return_serial");
+
+ if (serial == NULL)
+ return;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ serial_table[serial->minor + i] = NULL;
+ }
+
+ return;
+}
+
+
+#ifdef USES_EZUSB_FUNCTIONS
+/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
+#define CPUCS_REG 0x7F92
+
+int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
+{
+ int result;
+ unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL);
+
+// dbg("ezusb_writememory %x, %d", address, length);
+
+ if (!transfer_buffer) {
+ err("ezusb_writememory: kmalloc(%d) failed.", length);
+ return -ENOMEM;
+ }
+ memcpy (transfer_buffer, data, length);
+ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+ kfree (transfer_buffer);
+ return result;
+}
+
+
+int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+{
+ int response;
+ dbg("ezusb_set_reset: %d", reset_bit);
+ response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
+ if (response < 0) {
+ err("ezusb_set_reset %d failed", reset_bit);
+ }
+ return response;
+}
+
+#endif /* USES_EZUSB_FUNCTIONS */
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+static int serial_open (struct tty_struct *tty, struct file * filp)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ int portNumber;
+
+ dbg("serial_open");
+
+ /* initialize the pointer incase something fails */
+ tty->driver_data = NULL;
+
+ /* get the serial object associated with this tty pointer */
+ serial = get_serial_by_minor (MINOR(tty->device));
+
+ if (serial_paranoia_check (serial, "serial_open")) {
+ return -ENODEV;
+ }
+
+ /* set up our port structure */
+ portNumber = MINOR(tty->device) - serial->minor;
+ port = &serial->port[portNumber];
+ port->number = portNumber;
+ port->serial = serial;
+ port->magic = USB_SERIAL_PORT_MAGIC;
+
+ /* make the tty driver remember our port object, and us it */
+ tty->driver_data = port;
+ port->tty = tty;
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->open) {
+ return (serial->type->open(port, filp));
+ } else {
+ return (generic_open(port, filp));
+ }
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_close");
+
+ if (port_paranoia_check (port, "serial_close")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_close")) {
+ return;
+ }
+
+ dbg("serial_close port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not opened");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->close) {
+ serial->type->close(port, filp);
+ } else {
+ generic_close(port, filp);
+ }
+}
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_write");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
+ }
+
+ dbg("serial_write port %d, %d byte(s)", port->number, count);
+
+ if (!port->active) {
+ dbg ("port not opened");
+ return -EINVAL;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->write) {
+ return (serial->type->write(port, from_user, buf, count));
+ } else {
+ return (generic_write(port, from_user, buf, count));
+ }
+}
+
+
+static int serial_write_room (struct tty_struct *tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_write_room");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
+ }
+
+ dbg("serial_write_room port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->write_room) {
+ return (serial->type->write_room(port));
+ } else {
+ return (generic_write_room(port));
+ }
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_chars_in_buffer");
+
+ if (port_paranoia_check (port, "serial_chars_in_buffer")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ return -ENODEV;
+ }
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->chars_in_buffer) {
+ return (serial->type->chars_in_buffer(port));
+ } else {
+ return (generic_chars_in_buffer(port));
+ }
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_throttle");
+
+ if (port_paranoia_check (port, "serial_throttle")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_throttle")) {
+ return;
+ }
+
+ dbg("serial_throttle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function */
+ if (serial->type->throttle) {
+ serial->type->throttle(port);
+ }
+
+ return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_unthrottle");
+
+ if (port_paranoia_check (port, "serial_unthrottle")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_unthrottle")) {
+ return;
+ }
+
+ dbg("serial_unthrottle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function */
+ if (serial->type->unthrottle) {
+ serial->type->unthrottle(port);
+ }
+
+ return;
+}
+
+
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_ioctl");
+
+ if (port_paranoia_check (port, "serial_ioctl")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_ioctl")) {
+ return -ENODEV;
+ }
+
+ dbg("serial_ioctl port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -ENODEV;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->ioctl) {
+ return (serial->type->ioctl(port, file, cmd, arg));
+ } else {
+ return -ENOIOCTLCMD;
+ }
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_set_termios");
+
+ if (port_paranoia_check (port, "serial_set_termios")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_set_termios")) {
+ return;
+ }
+
+ dbg("serial_set_termios port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->set_termios) {
+ serial->type->set_termios(port, old);
+ }
+
+ return;
+}
+
+
+static void serial_break (struct tty_struct *tty, int break_state)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_break");
+
+ if (port_paranoia_check (port, "serial_break")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_break")) {
+ return;
+ }
+
+ dbg("serial_break port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function if it is
+ available */
+ if (serial->type->break_ctl) {
+ serial->type->break_ctl(port, break_state);
+ }
+}
+
+
+
+/*****************************************************************************
+ * generic devices specific driver functions
+ *****************************************************************************/
+static int generic_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /* if we have a bulk interrupt, start reading from it */
+ if (serial->num_bulk_in) {
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+ }
+
+ return (0);
+}
+
+
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_close port %d", port->number);
+
+ /* shutdown any bulk reads that might be going on */
+ if (serial->num_bulk_out) {
+ usb_unlink_urb (port->write_urb);
+ }
+ if (serial->num_bulk_in) {
+ usb_unlink_urb (port->read_urb);
+ }
+
+ port->active = 0;
+}
+
+
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_serial_write port %d", port->number);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
+ }
+ else {
+ memcpy (port->write_urb->transfer_buffer, buf, count);
+ }
+
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ dbg("usb_submit_urb(write bulk) failed");
+
+ return (count);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return (0);
+}
+
+
+static int generic_write_room (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ int room;
+
+ dbg("generic_write_room port %d", port->number);
+
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS)
+ room = 0;
+ else
+ room = port->bulk_out_size;
+ dbg("generic_write_room returns %d", room);
+ return (room);
+ }
+
+ return (0);
+}
+
+
+static int generic_chars_in_buffer (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_chars_in_buffer port %d", port->number);
+
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS) {
+ return (port->bulk_out_size);
+ }
+ }
+
+ return (0);
+}
+
+
+static void generic_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+
+ dbg("generic_read_bulk_callback");
+
+ if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ 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);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+}
+
+
+static void generic_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+
+ dbg("generic_write_bulk_callback");
+
+ if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ tty = port->tty;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ return;
+}
+
+
+static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
+{
+ struct tty_driver *serial_tty_driver;
+
+ if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
+ err("Out of memory");
+ return NULL;
+ }
+
+ memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
+
+ /* initialize the entries that we don't want to be NULL */
+ serial_tty_driver->magic = TTY_DRIVER_MAGIC;
+ serial_tty_driver->driver_name = driver_name;
+ serial_tty_driver->name = tty_driver_name;
+ serial_tty_driver->major = SERIAL_TTY_MAJOR;
+ serial_tty_driver->minor_start = serial->minor;
+ serial_tty_driver->num = serial->num_ports;
+ serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ serial_tty_driver->refcount = &serial_refcount;
+ serial_tty_driver->table = serial_tty;
+ serial_tty_driver->termios = serial_termios;
+ serial_tty_driver->termios_locked = serial_termios_locked;
+ serial_tty_driver->open = serial_open;
+ serial_tty_driver->close = serial_close;
+ serial_tty_driver->write = serial_write;
+ serial_tty_driver->write_room = serial_write_room;
+ serial_tty_driver->ioctl = serial_ioctl;
+ serial_tty_driver->set_termios = serial_set_termios;
+ serial_tty_driver->throttle = serial_throttle;
+ serial_tty_driver->unthrottle = serial_unthrottle;
+ serial_tty_driver->break_ctl = serial_break;
+ serial_tty_driver->chars_in_buffer = serial_chars_in_buffer;
+ serial_tty_driver->init_termios = tty_std_termios;
+ serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+ return serial_tty_driver;
+}
+
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_serial *serial = NULL;
+ struct usb_serial_port *port;
+ struct usb_interface_descriptor *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
+ struct usb_serial_device_type *type;
+ int device_num;
+ int minor;
+ int buffer_size;
+ int i;
+ char interrupt_pipe;
+ char bulk_in_pipe;
+ char bulk_out_pipe;
+ int num_interrupt_in = 0;
+ int num_bulk_in = 0;
+ int num_bulk_out = 0;
+ int num_ports;
+
+ /* loop through our list of known serial converters, and see if this device matches */
+ device_num = 0;
+ while (usb_serial_devices[device_num] != NULL) {
+ type = usb_serial_devices[device_num];
+ dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+
+ /* look at the device descriptor */
+ if ((dev->descriptor.idVendor == *(type->idVendor)) &&
+ (dev->descriptor.idProduct == *(type->idProduct))) {
+
+ dbg("descriptor matches...looking at the endpoints");
+
+ /* descriptor matches, let's try to find the endpoints needed */
+ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+
+ /* check out the endpoints */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ for (i = 0; i < interface->bNumEndpoints; ++i) {
+ endpoint = &interface->endpoint[i];
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+ bulk_in_pipe = HAS;
+ bulk_in_endpoint[num_bulk_in] = endpoint;
+ ++num_bulk_in;
+ }
+
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ bulk_out_pipe = HAS;
+ bulk_out_endpoint[num_bulk_out] = endpoint;
+ ++num_bulk_out;
+ }
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x03)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+ interrupt_pipe = HAS;
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+ ++num_interrupt_in;
+ }
+
+ }
+
+ /* verify that we found all of the endpoints that we need */
+ if ((interrupt_pipe & type->needs_interrupt_in) &&
+ (bulk_in_pipe & type->needs_bulk_in) &&
+ (bulk_out_pipe & type->needs_bulk_out)) {
+ /* found all that we need */
+ MOD_INC_USE_COUNT;
+ info("%s converter detected", type->name);
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+ if (type == &generic_device)
+ num_ports = num_bulk_out;
+ else
+#endif
+ num_ports = type->num_ports;
+
+ serial = get_free_serial (num_ports, &minor);
+ if (serial == NULL) {
+ err("No more free serial devices");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ serial->dev = dev;
+ serial->type = type;
+ serial->minor = minor;
+ serial->num_ports = num_ports;
+ serial->num_bulk_in = num_bulk_in;
+ serial->num_bulk_out = num_bulk_out;
+ serial->num_interrupt_in = num_interrupt_in;
+
+ /* initialize a tty_driver for this device */
+ serial->tty_driver = usb_serial_tty_driver_init (serial);
+ if (serial->tty_driver == NULL) {
+ err("Can't create a tty_serial_driver");
+ goto probe_error;
+ }
+
+ if (tty_register_driver (serial->tty_driver)) {
+ err("failed to register tty driver");
+ goto probe_error;
+ }
+
+ /* collect interrupt_in endpoints now, because
+ the keyspan_pda startup function needs
+ to know about them */
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
+ err("Couldn't allocate interrupt_in_buffer");
+ goto probe_error;
+ }
+ port->interrupt_in_endpoint = interrupt_in_endpoint[i];
+ }
+
+ /* if this device type has a startup function, call it */
+ if (type->startup) {
+ if (type->startup (serial)) {
+ goto probe_error;
+ }
+ }
+
+ /* set up the endpoint information */
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ port->read_urb = usb_alloc_urb (0);
+ if (!port->read_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
+ port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->bulk_in_buffer) {
+ err("Couldn't allocate bulk_in_buffer");
+ goto probe_error;
+ }
+ if (serial->type->read_bulk_callback) {
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
+ } else {
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
+ }
+ }
+
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ port->write_urb = usb_alloc_urb(0);
+ if (!port->write_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
+ port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
+ if (!port->bulk_out_buffer) {
+ err("Couldn't allocate bulk_out_buffer");
+ goto probe_error;
+ }
+ if (serial->type->write_bulk_callback) {
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
+ } else {
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
+ }
+ }
+
+#if 0 /* use this code when WhiteHEAT is up and running */
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ port->control_urb = usb_alloc_urb(0);
+ if (!port->control_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
+ err("Couldn't allocate interrupt_in_buffer");
+ goto probe_error;
+ }
+ FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
+ port->interrupt_in_buffer, buffer_size, serial_control_irq,
+ port, interrupt_in_endpoint[i]->bInterval);
+ }
+#endif
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
+ }
+
+ return serial;
+ } else {
+ info("descriptors matched, but endpoints did not");
+ }
+ }
+
+ /* look at the next type in our list */
+ ++device_num;
+ }
+
+probe_error:
+ if (serial) {
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb)
+ usb_free_urb (port->read_urb);
+ if (serial->port[i].bulk_in_buffer[i])
+ kfree (serial->port[i].bulk_in_buffer);
+ }
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb)
+ usb_free_urb (port->write_urb);
+ if (serial->port[i].bulk_out_buffer)
+ kfree (serial->port[i].bulk_out_buffer);
+ }
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->control_urb)
+ usb_free_urb (port->control_urb);
+ if (serial->port[i].interrupt_in_buffer)
+ kfree (serial->port[i].interrupt_in_buffer);
+ }
+
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
+ }
+
+ /* free up any memory that we allocated */
+ kfree (serial);
+ MOD_DEC_USE_COUNT;
+ }
+ return NULL;
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct usb_serial *serial = (struct usb_serial *) ptr;
+ struct usb_serial_port *port;
+ int i;
+
+ if (serial) {
+ for (i = 0; i < serial->num_ports; ++i)
+ serial->port[i].active = 0;
+
+ for (i = 0; i < serial->num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb) {
+ usb_unlink_urb (port->read_urb);
+ usb_free_urb (port->read_urb);
+ }
+ if (port->bulk_in_buffer)
+ kfree (port->bulk_in_buffer);
+ }
+ for (i = 0; i < serial->num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb) {
+ usb_unlink_urb (port->write_urb);
+ usb_free_urb (port->write_urb);
+ }
+ if (port->bulk_out_buffer)
+ kfree (port->bulk_out_buffer);
+ }
+ for (i = 0; i < serial->num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->control_urb) {
+ usb_unlink_urb (port->control_urb);
+ usb_free_urb (port->control_urb);
+ }
+ if (port->interrupt_in_buffer)
+ kfree (port->interrupt_in_buffer);
+ }
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+ }
+
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
+ }
+ /* free up any memory that we allocated */
+ kfree (serial);
+
+ } else {
+ info("device disconnected");
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+int usb_serial_init(void)
+{
+ int i;
+
+ /* Initalize our global data */
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ serial_table[i] = NULL;
+ }
+
+ /* register the USB driver */
+ if (usb_register(&usb_serial_driver) < 0) {
+ return -1;
+ }
+
+ info("support registered");
+ return 0;
+}
+
+
+void usb_serial_exit(void)
+{
+ usb_deregister(&usb_serial_driver);
+}
+
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+
+
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
new file mode 100644
index 000000000..6832814da
--- /dev/null
+++ b/drivers/usb/serial/visor.c
@@ -0,0 +1,209 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_VISOR
+
+#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 "visor.h"
+
+
+/* function prototypes for a handspring visor */
+static int visor_open (struct usb_serial_port *port, struct file *filp);
+static void visor_close (struct usb_serial_port *port, struct file *filp);
+static void visor_throttle (struct usb_serial_port *port);
+static void visor_unthrottle (struct usb_serial_port *port);
+static int visor_startup (struct usb_serial *serial);
+
+/* All of the device info needed for the Handspring Visor */
+static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
+static __u16 handspring_product_id = HANDSPRING_VISOR_ID;
+struct usb_serial_device_type handspring_device = {
+ name: "Handspring Visor",
+ idVendor: &handspring_vendor_id, /* the Handspring vendor ID */
+ idProduct: &handspring_product_id, /* the Handspring Visor product id */
+ needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 2,
+ num_bulk_out: 2,
+ num_ports: 2,
+ open: visor_open,
+ close: visor_close,
+ throttle: visor_throttle,
+ unthrottle: visor_unthrottle,
+ startup: visor_startup,
+};
+
+
+/******************************************************************************
+ * Handspring Visor specific driver functions
+ ******************************************************************************/
+static int visor_open (struct usb_serial_port *port, struct file *filp)
+{
+ dbg("visor_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+
+ port->active = 1;
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+
+ return (0);
+}
+
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+
+ dbg("visor_close port %d", port->number);
+
+ if (!transfer_buffer) {
+ err("visor_close: kmalloc(%d) failed.", 0x12);
+ } else {
+ /* send a shutdown message to the device */
+ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ }
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+}
+
+
+static void visor_throttle (struct usb_serial_port *port)
+{
+ dbg("visor_throttle port %d", port->number);
+
+ usb_unlink_urb (port->read_urb);
+
+ return;
+}
+
+
+static void visor_unthrottle (struct usb_serial_port *port)
+{
+ dbg("visor_unthrottle port %d", port->number);
+
+ if (usb_unlink_urb (port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+
+ return;
+}
+
+
+static int visor_startup (struct usb_serial *serial)
+{
+ int response;
+ int i;
+ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+ err("visor_startup: kmalloc(%d) failed.", 256);
+ return -ENOMEM;
+ }
+
+ dbg("visor_startup");
+
+ dbg("visor_setup: Set config to 1");
+ usb_set_configuration (serial->dev, 1);
+
+ /* send a get connection info request */
+ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ if (response < 0) {
+ err("visor_startup: error getting connection information");
+ } else {
+ struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
+ char *string;
+ info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
+ for (i = 0; i < connection_info->num_ports; ++i) {
+ switch (connection_info->connections[i].port_function_id) {
+ case VISOR_FUNCTION_GENERIC:
+ string = "Generic";
+ break;
+ case VISOR_FUNCTION_DEBUGGER:
+ string = "Debugger";
+ break;
+ case VISOR_FUNCTION_HOTSYNC:
+ string = "HotSync";
+ break;
+ case VISOR_FUNCTION_CONSOLE:
+ string = "Console";
+ break;
+ case VISOR_FUNCTION_REMOTE_FILE_SYS:
+ string = "Remote File System";
+ break;
+ default:
+ string = "unknown";
+ break;
+ }
+ info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
+ }
+ }
+
+ /* ask for the number of bytes available, but ignore the response as it is broken */
+ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
+ 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+ if (response < 0) {
+ err("visor_startup: error getting bytes available request");
+ }
+
+ kfree (transfer_buffer);
+
+ /* continue on with initialization */
+ return (0);
+}
+
+
+#endif /* CONFIG_USB_SERIAL_VISOR*/
+
+
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
new file mode 100644
index 000000000..a1173697d
--- /dev/null
+++ b/drivers/usb/serial/visor.h
@@ -0,0 +1,74 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_VISOR_H
+#define __LINUX_USB_SERIAL_VISOR_H
+
+
+#define HANDSPRING_VENDOR_ID 0x082d
+#define HANDSPRING_VISOR_ID 0x0100
+
+/****************************************************************************
+ * Handspring Visor Vendor specific request codes (bRequest values)
+ * A big thank you to Handspring for providing the following information.
+ * If anyone wants the original file where these values and structures came
+ * from, send email to <greg@kroah.com>.
+ ****************************************************************************/
+
+/****************************************************************************
+ * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
+ * are available to be transfered to the host for the specified endpoint.
+ * Currently this is not used, and always returns 0x0001
+ ****************************************************************************/
+#define VISOR_REQUEST_BYTES_AVAILABLE 0x01
+
+/****************************************************************************
+ * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
+ * is now closing the pipe. An empty packet is sent in response.
+ ****************************************************************************/
+#define VISOR_CLOSE_NOTIFICATION 0x02
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
+ * get the endpoints used by the connection.
+ ****************************************************************************/
+#define VISOR_GET_CONNECTION_INFORMATION 0x03
+
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
+ ****************************************************************************/
+struct visor_connection_info {
+ __u16 num_ports;
+ struct {
+ __u8 port_function_id;
+ __u8 port;
+ } connections[2];
+};
+
+
+/* struct visor_connection_info.connection[x].port defines: */
+#define VISOR_ENDPOINT_1 0x01
+#define VISOR_ENDPOINT_2 0x02
+
+/* struct visor_connection_info.connection[x].port_function_id defines: */
+#define VISOR_FUNCTION_GENERIC 0x00
+#define VISOR_FUNCTION_DEBUGGER 0x01
+#define VISOR_FUNCTION_HOTSYNC 0x02
+#define VISOR_FUNCTION_CONSOLE 0x03
+#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04
+
+#endif
+
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
new file mode 100644
index 000000000..aa6c14b0b
--- /dev/null
+++ b/drivers/usb/serial/whiteheat.c
@@ -0,0 +1,251 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+
+#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 "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
+
+
+#define CONNECT_TECH_VENDOR_ID 0x0710
+#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
+#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
+
+/* function prototypes for the Connect Tech WhiteHEAT serial converter */
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
+static void whiteheat_throttle (struct usb_serial_port *port);
+static void whiteheat_unthrottle (struct usb_serial_port *port);
+static int whiteheat_startup (struct usb_serial *serial);
+
+/* All of the device info needed for the Connect Tech WhiteHEAT */
+static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
+static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID;
+static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID;
+struct usb_serial_device_type whiteheat_fake_device = {
+ name: "Connect Tech - WhiteHEAT - (prerenumeration)",
+ idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
+ idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: whiteheat_startup
+};
+struct usb_serial_device_type whiteheat_device = {
+ name: "Connect Tech - WhiteHEAT",
+ idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
+ idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 4,
+ open: whiteheat_open,
+ close: whiteheat_close,
+ throttle: whiteheat_throttle,
+ unthrottle: whiteheat_unthrottle,
+ set_termios: whiteheat_set_termios,
+};
+
+
+/*****************************************************************************
+ * Connect Tech's White Heat specific driver functions
+ *****************************************************************************/
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
+{
+ dbg("whiteheat_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+
+ /* Need to do device specific setup here (control lines, baud rate, etc.) */
+ /* FIXME!!! */
+
+ return (0);
+}
+
+
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
+{
+ dbg("whiteheat_close port %d", port->number);
+
+ /* Need to change the control lines here */
+ /* FIXME */
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+}
+
+
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ dbg("whiteheat_set_termios port %d", port->number);
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("nothing to change...");
+ return;
+ }
+ }
+
+ /* do the parsing of the cflag to see what to set the line to */
+ /* FIXME!! */
+
+ return;
+}
+
+static void whiteheat_throttle (struct usb_serial_port *port)
+{
+ dbg("whiteheat_throttle port %d", port->number);
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+static void whiteheat_unthrottle (struct usb_serial_port *port)
+{
+ dbg("whiteheat_unthrottle port %d", port->number);
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+/* steps to download the firmware to the WhiteHEAT device:
+ - hold the reset (by writing to the reset bit of the CPUCS register)
+ - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
+ - release the reset (by writing to the CPUCS register)
+ - download the WH.HEX file for all addresses greater than 0x1b3f using
+ VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
+ - hold the reset
+ - download the WH.HEX file for all addresses less than 0x1b40 using
+ VENDOR_REQUEST_ANCHOR_LOAD
+ - release the reset
+ - device renumerated itself and comes up as new device id with all
+ firmware download completed.
+*/
+static int whiteheat_startup (struct usb_serial *serial)
+{
+ int response;
+ const struct whiteheat_hex_record *record;
+
+ dbg("whiteheat_startup");
+
+ response = ezusb_set_reset (serial, 1);
+
+ record = &whiteheat_loader[0];
+ while (record->address != 0xffff) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for loader (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 0);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ ++record;
+ }
+ while (record->address != 0xffff) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa3);
+ if (response < 0) {
+ err("ezusb_writememory failed for first firmware step (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 1);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for second firmware step (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 0);
+
+ /* we want this device to fail to have a driver assigned to it. */
+ return (1);
+}
+
+#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
+
+
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat_fw.h
index d7053e337..7d942ba00 100644
--- a/drivers/usb/serial/whiteheat.h
+++ b/drivers/usb/serial/whiteheat_fw.h
@@ -18,6 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * (04/09/2000) gkh
+ * Updated the firmware with the latest provided by ConnectTech.
+ *
* (01/16/2000) gkh
* Fixed my intel hex processing tool, so now the firmware actually
* matches the original file (this was causing a few problems...)
@@ -44,280 +47,271 @@ struct whiteheat_hex_record {
};
static const struct whiteheat_hex_record whiteheat_firmware[] = {
-{ 0x0000, 3, {0x02, 0x91, 0xc9} },
+{ 0x0000, 3, {0x02, 0x93, 0xa9} },
{ 0x0003, 3, {0x02, 0x13, 0x12} },
-{ 0x000b, 3, {0x02, 0x0a, 0x8d} },
-{ 0x0033, 3, {0x02, 0x07, 0x84} },
-{ 0x0043, 3, {0x02, 0x09, 0x00} },
-{ 0x0053, 3, {0x02, 0x0f, 0x6e} },
-{ 0x005b, 3, {0x02, 0x11, 0xb9} },
-{ 0x0300, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x03, 0x14, 0x70, 0x03, 0x02, 0x04, 0x77, 0x24} },
-{ 0x0310, 16, {0xfe, 0x70, 0x03, 0x02, 0x04, 0xca, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x03, 0xf4, 0x14, 0x70, 0x03} },
-{ 0x0320, 16, {0x02, 0x03, 0xe2, 0x14, 0x70, 0x03, 0x02, 0x03, 0xca, 0x14, 0x70, 0x03, 0x02, 0x03, 0xd9, 0x24} },
-{ 0x0330, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
-{ 0x0340, 16, {0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
-{ 0x0350, 16, {0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x58, 0xea, 0x49, 0x60, 0x0d} },
-{ 0x0360, 16, {0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0370, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08, 0xa9, 0xea} },
-{ 0x0380, 16, {0x49, 0x60, 0x33, 0x12, 0x9a, 0x48, 0xf5, 0x5e, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x5e, 0xd3} },
-{ 0x0390, 16, {0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x5e, 0x40} },
-{ 0x03a0, 16, {0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x5e, 0x12, 0x1b, 0x0c, 0x90, 0x7f, 0xb5} },
-{ 0x03b0, 16, {0xe5, 0x5e, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20} },
-{ 0x03c0, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
-{ 0x03d0, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
-{ 0x03e0, 16, {0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
-{ 0x03f0, 16, {0xa8, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
-{ 0x0400, 16, {0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
-{ 0x0410, 16, {0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
-{ 0x0420, 16, {0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0xe4} },
-{ 0x0430, 16, {0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90} },
-{ 0x0440, 16, {0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
-{ 0x0450, 16, {0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
-{ 0x0460, 16, {0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0470, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
-{ 0x0480, 16, {0x02, 0x60, 0x03, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
-{ 0x0490, 16, {0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x04a0, 16, {0x70, 0x1f, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54} },
-{ 0x04b0, 16, {0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x80} },
-{ 0x04c0, 16, {0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe} },
-{ 0x04d0, 16, {0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80} },
-{ 0x04e0, 16, {0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20} },
-{ 0x04f0, 16, {0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
-{ 0x0500, 16, {0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10} },
-{ 0x0510, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0520, 7, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
-{ 0x0527, 1, {0x22} },
-{ 0x0528, 16, {0x75, 0x5a, 0xff, 0x75, 0x59, 0xff, 0x75, 0x58, 0x0f, 0x75, 0x57, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
-{ 0x0538, 16, {0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
-{ 0x0548, 16, {0x01, 0x5b, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
-{ 0x0558, 16, {0x0a, 0xfa, 0xe4, 0x90, 0x02, 0x4d, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0568, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
-{ 0x0578, 16, {0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
-{ 0x0588, 16, {0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
-{ 0x0598, 16, {0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x05a8, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
-{ 0x05b8, 16, {0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x05c8, 16, {0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x05d8, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
-{ 0x05e8, 16, {0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
-{ 0x05f8, 16, {0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
-{ 0x0608, 16, {0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x62, 0x10, 0x75, 0x63, 0x02, 0x75} },
-{ 0x0618, 16, {0x64, 0x12, 0x75, 0x65, 0xac, 0x12, 0x8e, 0x35, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0xb2, 0x90, 0x01} },
-{ 0x0628, 16, {0x0d, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82} },
-{ 0x0638, 16, {0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x0648, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
-{ 0x0658, 16, {0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x0668, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x5d, 0xe5, 0x5d, 0xae, 0x5c, 0x70, 0x02, 0x05, 0x5c} },
-{ 0x0678, 16, {0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
-{ 0x0688, 16, {0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9b, 0xfb, 0x7e, 0x01} },
-{ 0x0698, 16, {0x7f, 0x18, 0x12, 0x84, 0x61, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x06a8, 16, {0xa3, 0xe0, 0xff, 0x75, 0x62, 0x0a, 0x75, 0x63, 0x06, 0x75, 0x64, 0x12, 0x75, 0x65, 0xb8, 0x12} },
-{ 0x06b8, 16, {0x8e, 0x35, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
-{ 0x06c8, 16, {0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
-{ 0x06d8, 16, {0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xa7, 0x75, 0x56, 0x50} },
-{ 0x06e8, 16, {0x75, 0x55, 0x6d, 0x75, 0x54, 0x33, 0x75, 0x53, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
-{ 0x06f8, 16, {0x7d, 0xff, 0x7c, 0xff, 0x78, 0x53, 0x12, 0x9b, 0xe4, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
-{ 0x0708, 16, {0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x00, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x08, 0xfb, 0x50} },
-{ 0x0718, 16, {0x06, 0x12, 0x0a, 0x00, 0x12, 0x09, 0xf4, 0xc2, 0x06, 0x12, 0x90, 0x58, 0x12, 0x98, 0x7d, 0xe4} },
-{ 0x0728, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0x5b} },
-{ 0x0738, 16, {0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
-{ 0x0748, 16, {0x80, 0x02, 0x7e, 0x00, 0x8e, 0x5b, 0x80, 0x03, 0x75, 0x5b, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
-{ 0x0758, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x5b, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
-{ 0x0768, 16, {0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x90, 0x02} },
-{ 0x0778, 11, {0x4d, 0xe0, 0x64, 0x0f, 0x70, 0x8b, 0x12, 0x93, 0x50, 0x80, 0x86} },
-{ 0x0783, 1, {0x22} },
-{ 0x0784, 4, {0x53, 0xd8, 0xef, 0x32} },
-{ 0x0788, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0x74, 0x89} },
-{ 0x0798, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x07a8, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff} },
-{ 0x07b8, 16, {0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
-{ 0x07c8, 16, {0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x07d8, 16, {0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
-{ 0x07e8, 16, {0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
-{ 0x07f8, 7, {0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x22} },
-{ 0x07ff, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
-{ 0x080f, 16, {0x08, 0x92, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92} },
-{ 0x081f, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x082f, 16, {0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x083f, 16, {0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
-{ 0x084f, 12, {0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x12, 0x0a, 0x00, 0x22} },
-{ 0x085b, 16, {0x90, 0x11, 0xef, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
-{ 0x086b, 16, {0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
-{ 0x087b, 16, {0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x07, 0x88, 0x75, 0x82, 0xef} },
-{ 0x088b, 7, {0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
-{ 0x0892, 16, {0x8e, 0x6d, 0x8f, 0x6e, 0xe5, 0x6e, 0x15, 0x6e, 0xae, 0x6d, 0x70, 0x02, 0x15, 0x6d, 0x4e, 0x60} },
-{ 0x08a2, 7, {0x05, 0x12, 0x08, 0xea, 0x80, 0xee, 0x22} },
-{ 0x08a9, 2, {0x8f, 0x5f} },
-{ 0x08ab, 16, {0xe4, 0xf5, 0x60, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x6a, 0xab, 0x61, 0xaa, 0x62} },
-{ 0x08bb, 16, {0xa9, 0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x03, 0x1d, 0xaf, 0x60, 0x05, 0x60, 0xef} },
-{ 0x08cb, 16, {0xb5, 0x5f, 0x01, 0x22, 0x12, 0x9a, 0x48, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
-{ 0x08db, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x08e9, 1, {0x22} },
-{ 0x08ea, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
-{ 0x08fa, 1, {0x22} },
-{ 0x08fb, 5, {0x12, 0x07, 0xff, 0xd3, 0x22} },
-{ 0x0900, 16, {0x02, 0x0b, 0x17, 0x00, 0x02, 0x0b, 0x4a, 0x00, 0x02, 0x0b, 0x2f, 0x00, 0x02, 0x0b, 0x89, 0x00} },
-{ 0x0910, 16, {0x02, 0x0b, 0x73, 0x00, 0x02, 0x09, 0xf9, 0x00, 0x02, 0x09, 0xfa, 0x00, 0x02, 0x09, 0xfb, 0x00} },
-{ 0x0920, 16, {0x02, 0x0b, 0xa4, 0x00, 0x02, 0x0c, 0x78, 0x00, 0x02, 0x0b, 0xd9, 0x00, 0x02, 0x0c, 0xc5, 0x00} },
-{ 0x0930, 16, {0x02, 0x0c, 0x0e, 0x00, 0x02, 0x0d, 0x12, 0x00, 0x02, 0x0c, 0x43, 0x00, 0x02, 0x0d, 0x5f, 0x00} },
-{ 0x0940, 16, {0x02, 0x09, 0xfc, 0x00, 0x02, 0x09, 0xfe, 0x00, 0x02, 0x09, 0xfd, 0x00, 0x02, 0x09, 0xff, 0x00} },
-{ 0x0950, 8, {0x02, 0x0d, 0xac, 0x00, 0x02, 0x0d, 0xc2, 0x00} },
-{ 0x0958, 16, {0xe4, 0xfe, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x12, 0xab, 0x61, 0xaa, 0x62, 0xa9} },
-{ 0x0968, 16, {0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
-{ 0x0978, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9a, 0xba, 0x85, 0xf0, 0x5f, 0xf5, 0x60, 0x62, 0x5f} },
-{ 0x0988, 16, {0xe5, 0x5f, 0x62, 0x60, 0xe5, 0x60, 0x62, 0x5f, 0x29, 0xfd, 0xe5, 0x5f, 0x3a, 0xa9, 0x05, 0x75} },
-{ 0x0998, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x09a6, 1, {0x22} },
-{ 0x09a7, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
-{ 0x09b7, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
-{ 0x09c7, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
-{ 0x09cc, 16, {0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
-{ 0x09dc, 16, {0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
-{ 0x09ec, 7, {0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
-{ 0x09f3, 1, {0x22} },
-{ 0x09f4, 5, {0x12, 0x07, 0x88, 0xd3, 0x22} },
-{ 0x09f9, 1, {0x32} },
-{ 0x09fa, 1, {0x32} },
-{ 0x09fb, 1, {0x32} },
-{ 0x09fc, 1, {0x32} },
-{ 0x09fd, 1, {0x32} },
-{ 0x09fe, 1, {0x32} },
-{ 0x09ff, 1, {0x32} },
-{ 0x0a00, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
-{ 0x0a7d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
-{ 0x0a8d, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
-{ 0x0a9d, 1, {0x07} },
-{ 0x0a9e, 16, {0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
-{ 0x0aae, 16, {0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
-{ 0x0abe, 16, {0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x02, 0x9e} },
-{ 0x0ace, 16, {0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
-{ 0x0ade, 13, {0x01, 0x5f, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x34, 0xff, 0xf0} },
-{ 0x0aeb, 15, {0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0afa, 16, {0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x0f, 0x72, 0x12, 0x08, 0x5b} },
-{ 0x0b0a, 13, {0x12, 0x0e, 0x0f, 0x12, 0x8f, 0x06, 0x12, 0x11, 0x9c, 0x12, 0x09, 0xcc, 0x22} },
-{ 0x0b17, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
-{ 0x0b27, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b2f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b3f, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b4a, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
-{ 0x0b5a, 16, {0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
-{ 0x0b6a, 9, {0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b73, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
-{ 0x0b83, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b89, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b99, 11, {0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0ba4, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x02, 0xf0, 0xe5} },
-{ 0x0bb4, 16, {0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20, 0x04, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bc4, 16, {0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0bd4, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0bd9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xe5} },
-{ 0x0be9, 16, {0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20, 0x0c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bf9, 16, {0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c09, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c0e, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xe5} },
-{ 0x0c1e, 16, {0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20, 0x14, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c2e, 16, {0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c3e, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c43, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x10, 0xf0, 0xe5} },
-{ 0x0c53, 16, {0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20, 0x1c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c63, 16, {0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c73, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c78, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0c88, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20, 0xe0, 0x06, 0x90, 0x7f, 0xc7} },
-{ 0x0c98, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0x90, 0x02, 0x96, 0xf0} },
-{ 0x0ca8, 16, {0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0cb8, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0cc5, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0cd5, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20, 0xe1, 0x06, 0x90, 0x7f, 0xc9} },
-{ 0x0ce5, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0x90, 0x02, 0x97, 0xf0} },
-{ 0x0cf5, 16, {0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d05, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d12, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d22, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20, 0xe2, 0x06, 0x90, 0x7f, 0xcb} },
-{ 0x0d32, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x90, 0x02, 0x98, 0xf0} },
-{ 0x0d42, 16, {0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d52, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d5f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d6f, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20, 0xe3, 0x06, 0x90, 0x7f, 0xcd} },
-{ 0x0d7f, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x90, 0x02, 0x99, 0xf0} },
-{ 0x0d8f, 16, {0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d9f, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dac, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
-{ 0x0dbc, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dc2, 16, {0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0} },
-{ 0x0dd2, 16, {0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x53, 0x91, 0xef} },
-{ 0x0de2, 16, {0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8c, 0xfb, 0x90, 0x7f, 0xd3} },
-{ 0x0df2, 16, {0xe4, 0xf0, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01} },
-{ 0x0e02, 13, {0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32} },
-{ 0x0e0f, 16, {0x90, 0x01, 0x20, 0x12, 0x9c, 0x07, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
-{ 0x0e1f, 16, {0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0e2f, 16, {0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50} },
-{ 0x0e3f, 16, {0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x84, 0xf4, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e4f, 16, {0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
-{ 0x0e5f, 16, {0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0x96, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4} },
-{ 0x0e6f, 16, {0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xdc, 0xe4} },
-{ 0x0e7f, 16, {0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e8f, 16, {0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02} },
-{ 0x0e9f, 16, {0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x82, 0xea, 0x90, 0x01, 0x1e} },
-{ 0x0eaf, 16, {0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0ebf, 16, {0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54} },
-{ 0x0ecf, 16, {0xf0, 0xfe, 0x74, 0x63, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xee, 0xf0, 0x74, 0x36} },
-{ 0x0edf, 16, {0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c, 0x2f, 0xf8, 0xe4, 0xf6} },
-{ 0x0eef, 16, {0x74, 0x9a, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0eff, 16, {0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0x5e, 0x60, 0x5e} },
-{ 0x0f0f, 16, {0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0xe7, 0x74} },
-{ 0x0f1f, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x5e, 0x60, 0x38, 0x90, 0x01} },
-{ 0x0f2f, 1, {0x1e} },
-{ 0x0f30, 16, {0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f40, 16, {0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f50, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x0f60, 14, {0x7d, 0x06, 0x12, 0x82, 0x60, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xa7, 0x22} },
-{ 0x0f6e, 4, {0x53, 0x91, 0xbf, 0x32} },
-{ 0x0f72, 16, {0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0xfd, 0x8b, 0x60, 0x75} },
-{ 0x0f82, 16, {0x61, 0x12, 0x75, 0x62, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x5e} },
-{ 0x0f92, 16, {0xf5, 0x5f, 0x90, 0x02, 0x4c, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
-{ 0x0fa2, 16, {0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
-{ 0x0fb2, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
-{ 0x0fc2, 16, {0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0x38, 0xab, 0x60, 0xaa, 0x61, 0xa9, 0x62} },
-{ 0x0fd2, 16, {0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0x27, 0x90, 0x00, 0x03} },
-{ 0x0fe2, 16, {0x12, 0x9a, 0x61, 0x64, 0x01, 0x60, 0x03, 0x02, 0x10, 0xae, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61} },
-{ 0x0ff2, 16, {0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x10, 0x88, 0xec, 0xc3, 0x94, 0x10} },
-{ 0x1002, 16, {0x40, 0x03, 0x02, 0x10, 0x88, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x5f, 0xae, 0x5e, 0x78, 0x02, 0xce} },
-{ 0x1012, 16, {0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
-{ 0x1022, 16, {0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
-{ 0x1032, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0x4c, 0xe0} },
-{ 0x1042, 16, {0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x5f, 0xae, 0x5e, 0x78} },
-{ 0x1052, 16, {0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x1062, 16, {0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
-{ 0x1072, 16, {0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
-{ 0x1082, 16, {0x4c, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0x25} },
-{ 0x1092, 16, {0x5f, 0xf5, 0x5f, 0xe4, 0x35, 0x5e, 0xf5, 0x5e, 0x90, 0x00, 0x05, 0x12, 0x9a, 0x61, 0xfe, 0xe4} },
-{ 0x10a2, 16, {0x25, 0x5f, 0xf5, 0x5f, 0xee, 0x35, 0x5e, 0xf5, 0x5e, 0x02, 0x11, 0x2a, 0xab, 0x60, 0xaa, 0x61} },
-{ 0x10b2, 16, {0xa9, 0x62, 0x90, 0x00, 0x03, 0x12, 0x9a, 0x61, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
-{ 0x10c2, 16, {0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
-{ 0x10d2, 16, {0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
-{ 0x10e2, 16, {0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
-{ 0x10f2, 16, {0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x1102, 16, {0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
-{ 0x1112, 16, {0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
-{ 0x1122, 16, {0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35} },
-{ 0x1132, 16, {0x61, 0xf5, 0x61, 0x02, 0x0f, 0xc3, 0x20, 0x03, 0x0d, 0x90, 0x02, 0x4c, 0xe0, 0x60, 0x07, 0x90} },
-{ 0x1142, 8, {0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
-{ 0x114a, 1, {0x22} },
-{ 0x114b, 2, {0xae, 0x07} },
-{ 0x114d, 16, {0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
-{ 0x115d, 16, {0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
-{ 0x116d, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
-{ 0x117d, 16, {0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
-{ 0x118d, 14, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
-{ 0x119b, 1, {0x22} },
-{ 0x119c, 16, {0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x7f, 0x05} },
-{ 0x11ac, 13, {0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x22} },
-{ 0x11b9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
-{ 0x11c9, 15, {0x53, 0x91, 0x7f, 0x90, 0x01, 0x62, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x11d8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
-{ 0x11e8, 7, {0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
-{ 0x11ef, 3, {0x00, 0x02, 0x28} },
+{ 0x000b, 3, {0x02, 0x0a, 0x80} },
+{ 0x0033, 3, {0x02, 0x08, 0x15} },
+{ 0x0043, 3, {0x02, 0x0a, 0x00} },
+{ 0x005b, 3, {0x02, 0x82, 0x31} },
+{ 0x0370, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x73, 0x14, 0x70, 0x03, 0x02, 0x04, 0xe7, 0x24} },
+{ 0x0380, 16, {0xfe, 0x70, 0x03, 0x02, 0x05, 0x45, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x64, 0x14, 0x70, 0x03} },
+{ 0x0390, 16, {0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x49, 0x24} },
+{ 0x03a0, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x94, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
+{ 0x03b0, 16, {0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x03c0, 16, {0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x7b, 0xea, 0x49, 0x60, 0x0d} },
+{ 0x03d0, 16, {0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x03e0, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x3a, 0xea} },
+{ 0x03f0, 16, {0x49, 0x60, 0x33, 0x12, 0x9b, 0x72, 0xf5, 0x4b, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x4b, 0xd3} },
+{ 0x0400, 16, {0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x4b, 0x40} },
+{ 0x0410, 16, {0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x4b, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xb5} },
+{ 0x0420, 16, {0xe5, 0x4b, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b} },
+{ 0x0430, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
+{ 0x0440, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
+{ 0x0450, 16, {0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
+{ 0x0460, 16, {0xa8, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
+{ 0x0470, 16, {0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
+{ 0x0480, 16, {0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
+{ 0x0490, 16, {0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0xe4} },
+{ 0x04a0, 16, {0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90} },
+{ 0x04b0, 16, {0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x04c0, 16, {0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
+{ 0x04d0, 16, {0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x04e0, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
+{ 0x04f0, 16, {0x02, 0x60, 0x03, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
+{ 0x0500, 16, {0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0510, 16, {0x70, 0x2a, 0x90, 0x7f, 0xec, 0xe0, 0xff, 0xf4, 0x54, 0x80, 0xfe, 0xc4, 0x54, 0x0f, 0xfe, 0xef} },
+{ 0x0520, 16, {0x54, 0x07, 0xfd, 0x2e, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4} },
+{ 0x0530, 16, {0xf0, 0x90, 0x7f, 0xd7, 0xed, 0xf0, 0xef, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0540, 16, {0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70} },
+{ 0x0550, 16, {0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0560, 16, {0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4} },
+{ 0x0570, 16, {0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x0580, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x0590, 16, {0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x05a0, 2, {0x02, 0xf0} },
+{ 0x05a2, 1, {0x22} },
+{ 0x05a3, 16, {0x75, 0x47, 0xff, 0x75, 0x46, 0xff, 0x75, 0x45, 0x0f, 0x75, 0x44, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
+{ 0x05b3, 16, {0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
+{ 0x05c3, 16, {0x01, 0xbc, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0xc0, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
+{ 0x05d3, 16, {0x0b, 0x8d, 0xe4, 0x90, 0x02, 0xaf, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x05e3, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
+{ 0x05f3, 16, {0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x49, 0x12, 0x75, 0x4a, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
+{ 0x0603, 16, {0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x0613, 16, {0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x0623, 16, {0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
+{ 0x0633, 16, {0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x0643, 16, {0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x0653, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
+{ 0x0663, 16, {0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
+{ 0x0673, 16, {0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
+{ 0x0683, 16, {0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x4f, 0x10, 0x75, 0x50, 0x02, 0x75} },
+{ 0x0693, 16, {0x51, 0x12, 0x75, 0x52, 0xac, 0x12, 0x90, 0x15, 0x75, 0x49, 0x12, 0x75, 0x4a, 0xb2, 0x90, 0x01} },
+{ 0x06a3, 16, {0x0d, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82} },
+{ 0x06b3, 16, {0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x06c3, 16, {0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
+{ 0x06d3, 16, {0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x06e3, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x4a, 0xe5, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x05, 0x49} },
+{ 0x06f3, 16, {0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
+{ 0x0703, 16, {0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9d, 0x25, 0x7e, 0x01} },
+{ 0x0713, 16, {0x7f, 0x18, 0x12, 0x85, 0x08, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x0723, 16, {0xa3, 0xe0, 0xff, 0x75, 0x4f, 0x0a, 0x75, 0x50, 0x06, 0x75, 0x51, 0x12, 0x75, 0x52, 0xb8, 0x12} },
+{ 0x0733, 16, {0x90, 0x15, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
+{ 0x0743, 16, {0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
+{ 0x0753, 16, {0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xca, 0x75, 0x43, 0x50} },
+{ 0x0763, 16, {0x75, 0x42, 0x6d, 0x75, 0x41, 0x33, 0x75, 0x40, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
+{ 0x0773, 16, {0x7d, 0xff, 0x7c, 0xff, 0x78, 0x40, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
+{ 0x0783, 16, {0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x70, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x0a, 0xed, 0x50} },
+{ 0x0793, 16, {0x06, 0x12, 0x0b, 0x00, 0x12, 0x0a, 0xf2, 0xc2, 0x06, 0x12, 0x92, 0x38, 0x90, 0x01, 0xbd, 0xe0} },
+{ 0x07a3, 16, {0x60, 0x10, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8e, 0xc1, 0xe4, 0x90, 0x01, 0xbd, 0xf0, 0x90, 0x7f} },
+{ 0x07b3, 16, {0xd3, 0xf0, 0x90, 0x02, 0xaf, 0xe0, 0xb4, 0x0f, 0x03, 0x12, 0x95, 0x30, 0x12, 0x99, 0xcc, 0xe4} },
+{ 0x07c3, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0xbc} },
+{ 0x07d3, 16, {0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
+{ 0x07e3, 16, {0x80, 0x02, 0x7e, 0x00, 0x8e, 0x48, 0x80, 0x03, 0x75, 0x48, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
+{ 0x07f3, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x48, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
+{ 0x0803, 16, {0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x02, 0x07} },
+{ 0x0813, 1, {0x84} },
+{ 0x0814, 1, {0x22} },
+{ 0x0815, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x0819, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0829, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x0839, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff} },
+{ 0x0849, 16, {0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
+{ 0x0859, 16, {0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x0869, 16, {0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
+{ 0x0879, 16, {0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
+{ 0x0889, 7, {0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x22} },
+{ 0x0890, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
+{ 0x08a0, 16, {0x09, 0x23, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23} },
+{ 0x08b0, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x08c0, 16, {0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x08d0, 16, {0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
+{ 0x08e0, 12, {0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x12, 0x0b, 0x00, 0x22} },
+{ 0x08ec, 16, {0x90, 0x11, 0xfc, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
+{ 0x08fc, 16, {0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
+{ 0x090c, 16, {0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x08, 0x19, 0x75, 0x82, 0xfc} },
+{ 0x091c, 7, {0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
+{ 0x0923, 16, {0x8e, 0x58, 0x8f, 0x59, 0xe5, 0x59, 0x15, 0x59, 0xae, 0x58, 0x70, 0x02, 0x15, 0x58, 0x4e, 0x60} },
+{ 0x0933, 7, {0x05, 0x12, 0x09, 0xef, 0x80, 0xee, 0x22} },
+{ 0x093a, 2, {0x8f, 0x4c} },
+{ 0x093c, 16, {0xe4, 0xf5, 0x4d, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x6a, 0xab, 0x4e, 0xaa, 0x4f} },
+{ 0x094c, 16, {0xa9, 0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x03, 0x1d, 0xaf, 0x4d, 0x05, 0x4d, 0xef} },
+{ 0x095c, 16, {0xb5, 0x4c, 0x01, 0x22, 0x12, 0x9b, 0x72, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x096c, 14, {0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x097a, 1, {0x22} },
+{ 0x097b, 16, {0xe4, 0xfe, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x12, 0xab, 0x4e, 0xaa, 0x4f, 0xa9} },
+{ 0x098b, 16, {0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x099b, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9b, 0xe4, 0x85, 0xf0, 0x4c, 0xf5, 0x4d, 0x62, 0x4c} },
+{ 0x09ab, 16, {0xe5, 0x4c, 0x62, 0x4d, 0xe5, 0x4d, 0x62, 0x4c, 0x29, 0xfd, 0xe5, 0x4c, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x09bb, 14, {0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x09c9, 1, {0x22} },
+{ 0x09ca, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
+{ 0x09da, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x09ea, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x09ef, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x09ff, 1, {0x22} },
+{ 0x0a00, 16, {0x02, 0x0b, 0xaa, 0x00, 0x02, 0x0b, 0xdd, 0x00, 0x02, 0x0b, 0xc2, 0x00, 0x02, 0x0c, 0x1c, 0x00} },
+{ 0x0a10, 16, {0x02, 0x0c, 0x06, 0x00, 0x02, 0x0a, 0xf7, 0x00, 0x02, 0x0a, 0xf8, 0x00, 0x02, 0x0a, 0xf9, 0x00} },
+{ 0x0a20, 16, {0x02, 0x0c, 0x37, 0x00, 0x02, 0x0d, 0x27, 0x00, 0x02, 0x0c, 0x73, 0x00, 0x02, 0x0d, 0x7b, 0x00} },
+{ 0x0a30, 16, {0x02, 0x0c, 0xaf, 0x00, 0x02, 0x0d, 0xcf, 0x00, 0x02, 0x0c, 0xeb, 0x00, 0x02, 0x0e, 0x23, 0x00} },
+{ 0x0a40, 16, {0x02, 0x0a, 0xfa, 0x00, 0x02, 0x0a, 0xfc, 0x00, 0x02, 0x0a, 0xfb, 0x00, 0x02, 0x0a, 0xfd, 0x00} },
+{ 0x0a50, 8, {0x02, 0x0e, 0x77, 0x00, 0x02, 0x0e, 0x8d, 0x00} },
+{ 0x0a58, 16, {0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
+{ 0x0a68, 16, {0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
+{ 0x0a78, 7, {0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
+{ 0x0a7f, 1, {0x22} },
+{ 0x0a80, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
+{ 0x0a90, 1, {0x07} },
+{ 0x0a91, 16, {0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
+{ 0x0aa1, 16, {0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
+{ 0x0ab1, 16, {0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x03, 0x00} },
+{ 0x0ac1, 16, {0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
+{ 0x0ad1, 13, {0x01, 0xc1, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x34, 0xff, 0xf0} },
+{ 0x0ade, 15, {0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0aed, 5, {0x12, 0x08, 0x90, 0xd3, 0x22} },
+{ 0x0af2, 5, {0x12, 0x08, 0x19, 0xd3, 0x22} },
+{ 0x0af7, 1, {0x32} },
+{ 0x0af8, 1, {0x32} },
+{ 0x0af9, 1, {0x32} },
+{ 0x0afa, 1, {0x32} },
+{ 0x0afb, 1, {0x32} },
+{ 0x0afc, 1, {0x32} },
+{ 0x0afd, 1, {0x32} },
+{ 0x0b00, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x0b7d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0b8d, 16, {0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x10, 0x0c, 0x12, 0x08, 0xec} },
+{ 0x0b9d, 13, {0x12, 0x0e, 0xa9, 0x12, 0x90, 0xe6, 0x12, 0x1b, 0x0c, 0x12, 0x0a, 0x58, 0x22} },
+{ 0x0baa, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0bba, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bc2, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0bd2, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bdd, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x0bed, 16, {0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
+{ 0x0bfd, 9, {0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c06, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0c16, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c1c, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c2c, 11, {0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c37, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c47, 16, {0xa9, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20} },
+{ 0x0c57, 16, {0x04, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0c67, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c73, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c83, 16, {0xa9, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20} },
+{ 0x0c93, 16, {0x0c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0ca3, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0caf, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cbf, 16, {0xa9, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20} },
+{ 0x0ccf, 16, {0x14, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0cdf, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ceb, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cfb, 16, {0xa9, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20} },
+{ 0x0d0b, 16, {0x1c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0d1b, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d27, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d37, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d47, 16, {0xe0, 0x06, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7} },
+{ 0x0d57, 16, {0xe0, 0x90, 0x02, 0xf8, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0d67, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0d77, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7b, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d8b, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d9b, 16, {0xe1, 0x06, 0x90, 0x7f, 0xc9, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9} },
+{ 0x0dab, 16, {0xe0, 0x90, 0x02, 0xf9, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0dbb, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0dcb, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dcf, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0ddf, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0def, 16, {0xe2, 0x06, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb} },
+{ 0x0dff, 16, {0xe0, 0x90, 0x02, 0xfa, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e0f, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e1f, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e23, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0e33, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0e43, 16, {0xe3, 0x06, 0x90, 0x7f, 0xcd, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd} },
+{ 0x0e53, 16, {0xe0, 0x90, 0x02, 0xfb, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e63, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e73, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e77, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
+{ 0x0e87, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e8d, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x90} },
+{ 0x0e9d, 12, {0x01, 0xbd, 0x74, 0xff, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ea9, 16, {0x90, 0x01, 0x20, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
+{ 0x0eb9, 16, {0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x13, 0xf0, 0xa3, 0x74} },
+{ 0x0ec9, 16, {0x11, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
+{ 0x0ed9, 16, {0xc3, 0x94, 0x04, 0x50, 0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x85, 0xe1} },
+{ 0x0ee9, 16, {0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90} },
+{ 0x0ef9, 16, {0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0f09, 16, {0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04} },
+{ 0x0f19, 16, {0xf0, 0x80, 0xdc, 0xe4, 0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0} },
+{ 0x0f29, 16, {0x90, 0x01, 0x1e, 0xe0, 0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8} },
+{ 0x0f39, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x83} },
+{ 0x0f49, 16, {0x5f, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0} },
+{ 0x0f59, 16, {0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x0f69, 16, {0xf5, 0x83, 0xe0, 0x54, 0xf0, 0xfe, 0x74, 0xc5, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83} },
+{ 0x0f79, 16, {0xee, 0xf0, 0x74, 0x36, 0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c} },
+{ 0x0f89, 16, {0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0xfc, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x0f99, 16, {0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f} },
+{ 0x0fa9, 16, {0xf5, 0x4b, 0x60, 0x5e, 0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94} },
+{ 0x0fb9, 16, {0x04, 0x50, 0xe7, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x4b} },
+{ 0x0fc9, 16, {0x60, 0x38, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4} },
+{ 0x0fd9, 16, {0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
+{ 0x0fe9, 16, {0x34, 0x20, 0xf5, 0x83, 0xe0, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0ff9, 16, {0x20, 0xf5, 0x83, 0xe0, 0xfe, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0} },
+{ 0x1009, 3, {0x80, 0xa7, 0x22} },
+{ 0x100c, 16, {0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0xfd, 0x8b, 0x4d, 0x75} },
+{ 0x101c, 16, {0x4e, 0x12, 0x75, 0x4f, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x4b} },
+{ 0x102c, 16, {0xf5, 0x4c, 0x90, 0x02, 0xae, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
+{ 0x103c, 16, {0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x104c, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
+{ 0x105c, 16, {0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0xd2, 0xab, 0x4d, 0xaa, 0x4e, 0xa9, 0x4f} },
+{ 0x106c, 16, {0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0xc1, 0x90, 0x00, 0x03} },
+{ 0x107c, 16, {0x12, 0x9b, 0x8b, 0x64, 0x01, 0x60, 0x03, 0x02, 0x11, 0x48, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b} },
+{ 0x108c, 16, {0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x11, 0x22, 0xec, 0xc3, 0x94, 0x10} },
+{ 0x109c, 16, {0x40, 0x03, 0x02, 0x11, 0x22, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x4c, 0xae, 0x4b, 0x78, 0x02, 0xce} },
+{ 0x10ac, 16, {0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x10bc, 16, {0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
+{ 0x10cc, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0xae, 0xe0} },
+{ 0x10dc, 16, {0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x4c, 0xae, 0x4b, 0x78} },
+{ 0x10ec, 16, {0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x10fc, 16, {0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
+{ 0x110c, 16, {0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
+{ 0x111c, 16, {0xae, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0x25} },
+{ 0x112c, 16, {0x4c, 0xf5, 0x4c, 0xe4, 0x35, 0x4b, 0xf5, 0x4b, 0x90, 0x00, 0x05, 0x12, 0x9b, 0x8b, 0xfe, 0xe4} },
+{ 0x113c, 16, {0x25, 0x4c, 0xf5, 0x4c, 0xee, 0x35, 0x4b, 0xf5, 0x4b, 0x02, 0x11, 0xc4, 0xab, 0x4d, 0xaa, 0x4e} },
+{ 0x114c, 16, {0xa9, 0x4f, 0x90, 0x00, 0x03, 0x12, 0x9b, 0x8b, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
+{ 0x115c, 16, {0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
+{ 0x116c, 16, {0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
+{ 0x117c, 16, {0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
+{ 0x118c, 16, {0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x119c, 16, {0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
+{ 0x11ac, 16, {0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
+{ 0x11bc, 16, {0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35} },
+{ 0x11cc, 16, {0x4e, 0xf5, 0x4e, 0x02, 0x10, 0x5d, 0x20, 0x03, 0x0d, 0x90, 0x02, 0xae, 0xe0, 0x60, 0x07, 0x90} },
+{ 0x11dc, 8, {0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
+{ 0x11e4, 1, {0x22} },
+{ 0x11e5, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
+{ 0x11f5, 7, {0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
+{ 0x11fc, 3, {0x00, 0x03, 0x15} },
{ 0x1200, 16, {0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
{ 0x1210, 16, {0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
{ 0x1220, 16, {0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
@@ -455,40 +449,39 @@ static const struct whiteheat_hex_record whiteheat_firmware[] = {
{ 0x1a35, 16, {0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
{ 0x1a45, 16, {0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
{ 0x1a55, 16, {0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x1a65, 16, {0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x69, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
+{ 0x1a65, 16, {0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x54, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
{ 0x1a75, 16, {0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
{ 0x1a85, 16, {0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x1a95, 16, {0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x1a95, 16, {0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
{ 0x1aa5, 16, {0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
-{ 0x1ab5, 16, {0x9a, 0x8e, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
+{ 0x1ab5, 16, {0x9b, 0xb8, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
{ 0x1ac5, 16, {0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
-{ 0x1ad5, 16, {0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x69, 0x30, 0xe0, 0xf7, 0x30} },
+{ 0x1ad5, 16, {0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x54, 0x30, 0xe0, 0xf7, 0x30} },
{ 0x1ae5, 16, {0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
-{ 0x1af5, 16, {0x19, 0xc7, 0xe5, 0x69, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
+{ 0x1af5, 16, {0x19, 0xc7, 0xe5, 0x54, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
{ 0x1b05, 6, {0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
{ 0x1b0b, 1, {0x22} },
-{ 0x1b0c, 16, {0x8e, 0x5f, 0x8f, 0x60, 0x8c, 0x61, 0x8d, 0x62, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x60} },
-{ 0x1b1c, 16, {0xe5, 0x60, 0xae, 0x5f, 0x70, 0x02, 0x05, 0x5f, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
-{ 0x1b2c, 16, {0x62, 0xe5, 0x62, 0xac, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x1b3c, 3, {0x80, 0xd6, 0x22} },
-{ 0x8000, 4, {0x8e, 0x69, 0x8f, 0x6a} },
-{ 0x8004, 16, {0x75, 0x6b, 0x03, 0xe5, 0x6a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x8014, 16, {0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x6b, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
+{ 0x1b0c, 16, {0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x7f, 0x05} },
+{ 0x1b1c, 13, {0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x22} },
+{ 0x1b29, 16, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
+{ 0x8000, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8004, 16, {0x75, 0x56, 0x03, 0xe5, 0x55, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x8014, 16, {0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x56, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
{ 0x8024, 16, {0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x8034, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
-{ 0x8044, 16, {0x80, 0x6c, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
-{ 0x8054, 16, {0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x6b, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3} },
-{ 0x8064, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x6a, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x8074, 16, {0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5} },
-{ 0x8084, 16, {0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x6a, 0x24} },
-{ 0x8094, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9a, 0x8e, 0x85} },
-{ 0x80a4, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0x8e, 0x90, 0x7f} },
-{ 0x80b4, 16, {0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
-{ 0x80c4, 16, {0x22, 0xe5, 0x6c, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
-{ 0x80d4, 16, {0xe5, 0x6b, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x80e4, 16, {0x80, 0xf0, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
-{ 0x80f4, 16, {0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
-{ 0x8104, 12, {0x6b, 0x03, 0x02, 0x80, 0x07, 0x15, 0x6b, 0x02, 0x80, 0x07, 0x7f, 0x08} },
+{ 0x8034, 16, {0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8044, 16, {0x80, 0x6c, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
+{ 0x8054, 16, {0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x56, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8064, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x8074, 16, {0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5} },
+{ 0x8084, 16, {0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x55, 0x24} },
+{ 0x8094, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9b, 0xb8, 0x85} },
+{ 0x80a4, 16, {0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xb8, 0x90, 0x7f} },
+{ 0x80b4, 16, {0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
+{ 0x80c4, 16, {0x22, 0xe5, 0x57, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
+{ 0x80d4, 16, {0xe5, 0x56, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x80e4, 16, {0x80, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
+{ 0x80f4, 16, {0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
+{ 0x8104, 12, {0x56, 0x03, 0x02, 0x80, 0x07, 0x15, 0x56, 0x02, 0x80, 0x07, 0x7f, 0x08} },
{ 0x8110, 1, {0x22} },
{ 0x8111, 2, {0xac, 0x07} },
{ 0x8113, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
@@ -505,476 +498,497 @@ static const struct whiteheat_hex_record whiteheat_firmware[] = {
{ 0x81c3, 16, {0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
{ 0x81d3, 12, {0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
{ 0x81df, 1, {0x22} },
-{ 0x81e0, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
-{ 0x81f0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf9, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0} },
-{ 0x8200, 16, {0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8210, 16, {0xa3, 0xf0, 0xed, 0x60, 0x29, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33} },
-{ 0x8220, 16, {0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4, 0xef, 0x55, 0x3b, 0x60, 0x0a, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8230, 16, {0xa3, 0x74, 0x01, 0xf0, 0x80, 0x08, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0x74, 0xad, 0xf0, 0x8b, 0x82} },
-{ 0x8240, 16, {0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54} },
-{ 0x8250, 15, {0xef, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe9, 0xf0} },
-{ 0x825f, 1, {0x22} },
-{ 0x8260, 4, {0x8f, 0x68, 0x8d, 0x69} },
-{ 0x8264, 16, {0xe4, 0xf5, 0x6a, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
-{ 0x8274, 16, {0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x8284, 16, {0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x50} },
-{ 0x8294, 16, {0x3c, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x82a4, 16, {0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
-{ 0x82b4, 16, {0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75, 0x6a, 0x40, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76} },
-{ 0x82c4, 16, {0x10, 0x80, 0x0a, 0x75, 0x6a, 0x80, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76, 0x38, 0xe5, 0x6a, 0x45} },
-{ 0x82d4, 16, {0x69, 0x44, 0x01, 0xff, 0xe5, 0x68, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x82e4, 5, {0x20, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x82e9, 1, {0x22} },
-{ 0x82ea, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x82fa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xf5, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5} },
-{ 0x830a, 16, {0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82} },
-{ 0x831a, 16, {0x60, 0xaf, 0x5f, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3} },
-{ 0x832a, 16, {0xe0, 0x20, 0xe0, 0x28, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x61} },
-{ 0x833a, 16, {0xf5, 0x83, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83} },
-{ 0x834a, 16, {0xe0, 0xf5, 0x60, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x80, 0xcc, 0x74, 0x96, 0x25, 0x5f} },
-{ 0x835a, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x5f, 0x25, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x836a, 16, {0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82} },
-{ 0x837a, 16, {0xfe, 0xe5, 0x5f, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0} },
-{ 0x838a, 16, {0xa3, 0xef, 0xf0, 0xaf, 0x5f, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc} },
-{ 0x839a, 4, {0x42, 0x30, 0x7f, 0x00} },
-{ 0x839e, 1, {0x22} },
-{ 0x839f, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x47, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x83af, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x49, 0x8f, 0x4a, 0x74, 0x96, 0x25, 0x47, 0xf5, 0x82, 0xe4} },
-{ 0x83bf, 16, {0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x4a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5} },
-{ 0x83cf, 16, {0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf, 0x47, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0xaf, 0x47, 0x7d, 0x06} },
-{ 0x83df, 16, {0x12, 0x82, 0x60, 0xe5, 0x4a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5, 0x83, 0xe0, 0x30} },
-{ 0x83ef, 16, {0xe0, 0x0b, 0x85, 0x4a, 0x82, 0x85, 0x49, 0x83, 0xe0, 0xf5, 0x48, 0x80, 0xe6, 0xaf, 0x47, 0x74} },
-{ 0x83ff, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x47, 0x25} },
-{ 0x840f, 13, {0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xff} },
-{ 0x841c, 1, {0x22} },
-{ 0x841d, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8421, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x49, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
-{ 0x8431, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x48, 0x82, 0x8e, 0x83, 0xa3} },
-{ 0x8441, 16, {0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x49, 0x7d, 0x02, 0x12, 0x82, 0x60, 0x85, 0x48, 0x82, 0x85, 0x47} },
-{ 0x8451, 15, {0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x49, 0x7d, 0x04, 0x12, 0x82, 0x60, 0x7f, 0x00} },
-{ 0x8460, 1, {0x22} },
-{ 0x8461, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
-{ 0x8471, 16, {0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x8481, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
-{ 0x8491, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
-{ 0x84a1, 16, {0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
-{ 0x84b1, 16, {0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
-{ 0x84c1, 16, {0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
-{ 0x84d1, 16, {0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x84e1, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
-{ 0x84f1, 3, {0x83, 0xf0, 0x22} },
-{ 0x84f4, 4, {0x8e, 0x5f, 0x8f, 0x60} },
-{ 0x84f8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x8508, 16, {0x1f, 0xad, 0x82, 0xf5, 0x66, 0x8d, 0x67, 0xaa, 0x5f, 0xa9, 0x60, 0x7b, 0x01, 0xc0, 0x03, 0xc0} },
-{ 0x8518, 16, {0x01, 0xef, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x92, 0xf9, 0x74, 0x02, 0x35, 0xf0, 0xa8, 0x01, 0xfc} },
-{ 0x8528, 16, {0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9a, 0x1f, 0x85, 0x60, 0x82} },
-{ 0x8538, 16, {0x85, 0x5f, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0x7f} },
-{ 0x8548, 16, {0x00, 0x7e, 0x08, 0x7d, 0x07, 0x7c, 0x00, 0x12, 0x9b, 0x2e, 0x8f, 0x64, 0x8e, 0x63, 0x8d, 0x62} },
-{ 0x8558, 16, {0x8c, 0x61, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x70, 0x09} },
-{ 0x8568, 16, {0x75, 0x64, 0x01, 0xf5, 0x63, 0xf5, 0x62, 0xf5, 0x61, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0x00, 0x7c} },
-{ 0x8578, 16, {0x00, 0xab, 0x64, 0xaa, 0x63, 0xa9, 0x62, 0xa8, 0x61, 0xd3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75} },
-{ 0x8588, 16, {0x64, 0xff, 0x75, 0x63, 0xff, 0x75, 0x62, 0x00, 0x75, 0x61, 0x00, 0x85, 0x67, 0x82, 0x85, 0x66} },
-{ 0x8598, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xe5, 0x64} },
-{ 0x85a8, 16, {0xf0, 0xaf, 0x64, 0xae, 0x63, 0xad, 0x62, 0xac, 0x61, 0x78, 0x08, 0x12, 0x9b, 0xd1, 0x85, 0x67} },
-{ 0x85b8, 16, {0x82, 0x85, 0x66, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x85c8, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x65, 0xe5, 0x60, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x5f} },
-{ 0x85d8, 16, {0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x65, 0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05} },
-{ 0x85e8, 16, {0x43, 0x65, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03, 0x43, 0x65, 0x02, 0xe5, 0x60, 0x24, 0x0b} },
-{ 0x85f8, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe3, 0x03, 0x43, 0x65, 0x80, 0xef} },
-{ 0x8608, 16, {0x30, 0xe7, 0x12, 0x43, 0x65, 0x40, 0xe5, 0x67, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x8618, 16, {0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x60, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83} },
-{ 0x8628, 16, {0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x27, 0x85, 0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14} },
-{ 0x8638, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x67} },
-{ 0x8648, 16, {0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x17, 0x85} },
-{ 0x8658, 16, {0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x8668, 16, {0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x3b, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0x74} },
-{ 0x8678, 16, {0xbf, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x65, 0xf0, 0xe5} },
-{ 0x8688, 16, {0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x04} },
-{ 0x8698, 16, {0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4} },
-{ 0x86a8, 16, {0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x86b8, 16, {0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff} },
-{ 0x86c8, 16, {0xe5, 0x67, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24} },
-{ 0x86d8, 16, {0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x07, 0xf5, 0x82} },
-{ 0x86e8, 16, {0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x86f8, 16, {0xe4, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x60, 0x82, 0x85, 0x5f} },
-{ 0x8708, 16, {0x83, 0xe0, 0x14, 0xff, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x75, 0x65, 0x08, 0xe5, 0x60, 0x24, 0x0c} },
-{ 0x8718, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43, 0x65, 0x10, 0xe5, 0x67, 0x24} },
-{ 0x8728, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x45, 0x65, 0xf0, 0xe5, 0x60} },
-{ 0x8738, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x14, 0xff, 0x25, 0xe0, 0x25, 0xe0} },
-{ 0x8748, 16, {0xff, 0xe5, 0x60, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xfb, 0x4f} },
-{ 0x8758, 16, {0xf5, 0x65, 0xe5, 0x60, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xd0} },
-{ 0x8768, 16, {0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a, 0x70, 0x12, 0x43, 0x65, 0x18} },
-{ 0x8778, 16, {0x80, 0x0d, 0x43, 0x65, 0x08, 0x80, 0x08, 0x43, 0x65, 0x38, 0x80, 0x03, 0x43, 0x65, 0x28, 0x85} },
-{ 0x8788, 13, {0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x65, 0xf0, 0x7f, 0x00} },
-{ 0x8795, 1, {0x22} },
-{ 0x8796, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x879a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x4a, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x87aa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4d, 0x8f, 0x4e, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01} },
-{ 0x87ba, 16, {0xf5, 0x4c, 0xe4, 0x3e, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x08, 0xf0, 0xe5, 0x4a, 0x04} },
-{ 0x87ca, 16, {0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xf0, 0xa3, 0xe4, 0xf0, 0xe5, 0x4e, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x87da, 16, {0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xf0, 0xe5} },
-{ 0x87ea, 16, {0x4e, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x85, 0x4c, 0x82} },
-{ 0x87fa, 16, {0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xa3, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x2b} },
-{ 0x880a, 16, {0xf8, 0xe6, 0xff, 0xe5, 0x4c, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x881a, 16, {0xaf, 0x4a, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x49, 0x7f} },
-{ 0x882a, 16, {0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x49, 0x5f, 0xff} },
-{ 0x883a, 16, {0xe5, 0x4c, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x884a, 5, {0x74, 0x07, 0xf0, 0x7f, 0x00} },
-{ 0x884f, 1, {0x22} },
-{ 0x8850, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x8860, 16, {0xaf, 0x82, 0xf5, 0x47, 0x8f, 0x48, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e} },
-{ 0x8870, 16, {0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0a, 0xf0, 0xe5, 0x48, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
-{ 0x8880, 16, {0x47, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x90, 0x7f, 0xc3, 0x74, 0x02, 0xf0, 0x7f} },
-{ 0x8890, 1, {0x00} },
-{ 0x8891, 1, {0x22} },
-{ 0x8892, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88a2, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88b2, 16, {0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88c2, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
-{ 0x88cd, 1, {0x22} },
-{ 0x88ce, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88de, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88ee, 16, {0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88fe, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
-{ 0x8909, 1, {0x22} },
-{ 0x890a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x891a, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x892a, 16, {0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
-{ 0x893a, 7, {0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
-{ 0x8941, 1, {0x22} },
-{ 0x8942, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8946, 16, {0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
-{ 0x8956, 16, {0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
-{ 0x8966, 16, {0x49, 0x7e, 0x75, 0x4a, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x49, 0x7e, 0x75, 0x4a} },
-{ 0x8976, 16, {0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x80, 0x80, 0x0a, 0x7e} },
-{ 0x8986, 16, {0x7d, 0x7f, 0x00, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x00, 0xe5, 0x4b, 0x70, 0x20, 0x85, 0x4a, 0x82} },
-{ 0x8996, 16, {0x85, 0x49, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
-{ 0x89a6, 16, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x3a, 0xe5, 0x48, 0x24} },
-{ 0x89b6, 16, {0x02, 0xff, 0xe4, 0x35, 0x47, 0xfe, 0xe5, 0x4b, 0x60, 0x10, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x85} },
-{ 0x89c6, 16, {0x4a, 0x82, 0x85, 0x49, 0x83, 0xf0, 0x15, 0x4b, 0x80, 0xec, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x89d6, 16, {0xa3, 0xe0, 0xff, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24, 0xb5, 0xf5, 0x82} },
-{ 0x89e6, 9, {0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
-{ 0x89ef, 1, {0x22} },
-{ 0x89f0, 16, {0xef, 0x24, 0x01, 0xf5, 0x48, 0xe4, 0x3e, 0xf5, 0x47, 0x7c, 0x7b, 0x7d, 0x80, 0x7e, 0x7b, 0x7f} },
-{ 0x8a00, 16, {0x80, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x07, 0xf0, 0xef, 0x24, 0x01, 0xff, 0xe4, 0x3e, 0x90, 0x01} },
-{ 0x8a10, 16, {0x31, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xfe} },
-{ 0x8a20, 16, {0xa3, 0xe0, 0x8e, 0x49, 0xf5, 0x4a, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x60} },
-{ 0x8a30, 16, {0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8a, 0xdd, 0x24, 0x14, 0x60, 0x03} },
-{ 0x8a40, 16, {0x02, 0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3} },
-{ 0x8a50, 16, {0xe4, 0x9f, 0xf5, 0x4c, 0x74, 0x01, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b} },
-{ 0x8a60, 16, {0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5} },
-{ 0x8a70, 16, {0x49, 0x95, 0x4b, 0x50, 0x03, 0x02, 0x8b, 0x30, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85} },
-{ 0x8a80, 16, {0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x02} },
-{ 0x8a90, 16, {0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x8aa0, 16, {0x30, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b, 0x94} },
-{ 0x8ab0, 16, {0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5, 0x49} },
-{ 0x8ac0, 16, {0x95, 0x4b, 0x40, 0x6c, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3} },
-{ 0x8ad0, 16, {0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x80, 0x53, 0x85, 0x48, 0x82} },
-{ 0x8ae0, 16, {0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e} },
-{ 0x8af0, 16, {0xf5, 0x4b, 0x45, 0x4c, 0x70, 0x07, 0xf5, 0x4b, 0x75, 0x4c, 0x40, 0x80, 0x11, 0xd3, 0xe5, 0x4c} },
-{ 0x8b00, 16, {0x94, 0x40, 0xe5, 0x4b, 0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5} },
-{ 0x8b10, 16, {0x4a, 0x95, 0x4c, 0xe5, 0x49, 0x95, 0x4b, 0x40, 0x17, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82} },
-{ 0x8b20, 16, {0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a} },
-{ 0x8b30, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8b, 0xf0, 0x24, 0xf9} },
-{ 0x8b40, 16, {0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x40, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x84} },
-{ 0x8b50, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
-{ 0x8b60, 16, {0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a} },
-{ 0x8b70, 16, {0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xe0} },
-{ 0x8b80, 16, {0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a} },
-{ 0x8b90, 16, {0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x8ba0, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8c} },
-{ 0x8bb0, 16, {0x84, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2d} },
-{ 0x8bc0, 16, {0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02} },
-{ 0x8bd0, 16, {0x8c, 0x84, 0x90, 0x01, 0x2d, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8be0, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
-{ 0x8bf0, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
-{ 0x8c00, 16, {0x94, 0x00, 0x50, 0x03, 0x02, 0x8c, 0x84, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
-{ 0x8c10, 16, {0x90, 0x01, 0x2e, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e} },
-{ 0x8c20, 16, {0x60, 0x62, 0x90, 0x01, 0x2e, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8c30, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
-{ 0x8c40, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x2f, 0xcf, 0xf0} },
-{ 0x8c50, 16, {0xa3, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x60, 0x24} },
-{ 0x8c60, 16, {0x90, 0x01, 0x2f, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
-{ 0x8c70, 16, {0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
-{ 0x8c80, 16, {0xef, 0xf0, 0x80, 0xcf, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xa3, 0xe0} },
-{ 0x8c90, 6, {0x90, 0x7f, 0xc3, 0xf0, 0x7f, 0x00} },
-{ 0x8c96, 1, {0x22} },
-{ 0x8c97, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e, 0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74} },
-{ 0x8ca7, 16, {0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f, 0x8d, 0x82, 0x8c, 0x83} },
-{ 0x8cb7, 16, {0xf0, 0x90, 0x11, 0xf0, 0xe4, 0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xf0, 0x90, 0x11, 0xf1, 0xe4} },
-{ 0x8cc7, 16, {0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xf0, 0xe4, 0x90, 0x01, 0x33, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x8cd7, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xed, 0x24, 0x03, 0xfe, 0xe4, 0x3c, 0xa3} },
-{ 0x8ce7, 16, {0xf0, 0xa3, 0xce, 0xf0, 0x7e, 0x01, 0x7f, 0x33, 0x12, 0x19, 0xc1, 0x90, 0x7f, 0xc3, 0x74, 0x14} },
-{ 0x8cf7, 3, {0xf0, 0x7f, 0x00} },
-{ 0x8cfa, 1, {0x22} },
-{ 0x8cfb, 4, {0x8e, 0x40, 0x8f, 0x41} },
-{ 0x8cff, 16, {0x85, 0x40, 0x43, 0x85, 0x41, 0x44, 0x85, 0x44, 0x82, 0x85, 0x43, 0x83, 0xe0, 0x14, 0xb4, 0x0f} },
-{ 0x8d0f, 16, {0x00, 0x40, 0x03, 0x02, 0x8e, 0x32, 0x90, 0x8d, 0x1c, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8d, 0x49} },
-{ 0x8d1f, 16, {0x02, 0x8d, 0x5a, 0x02, 0x8d, 0x6b, 0x02, 0x8d, 0x8e, 0x02, 0x8d, 0x9f, 0x02, 0x8d, 0xb0, 0x02} },
-{ 0x8d2f, 16, {0x8d, 0xc0, 0x02, 0x8d, 0xcb, 0x02, 0x8d, 0xdb, 0x02, 0x8d, 0xeb, 0x02, 0x8d, 0xfb, 0x02, 0x8e} },
-{ 0x8d3f, 16, {0x02, 0x02, 0x8e, 0x32, 0x02, 0x8e, 0x12, 0x02, 0x8e, 0x22, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4} },
-{ 0x8d4f, 16, {0x35, 0x43, 0xfe, 0x12, 0x82, 0xea, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01, 0xff} },
-{ 0x8d5f, 16, {0xe4, 0x35, 0x43, 0xfe, 0x12, 0x83, 0x9f, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8d6f, 16, {0xf5, 0x46, 0xe4, 0x35, 0x43, 0xf5, 0x45, 0xe5, 0x46, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x45, 0xfe} },
-{ 0x8d7f, 16, {0x12, 0x84, 0x61, 0xaf, 0x46, 0xae, 0x45, 0x12, 0x84, 0xf4, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5} },
-{ 0x8d8f, 16, {0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x92, 0x8f, 0x42, 0x02, 0x8e, 0x32} },
-{ 0x8d9f, 16, {0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0xce, 0x8f, 0x42, 0x02, 0x8e} },
-{ 0x8daf, 16, {0x32, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x0a, 0x8f, 0x42, 0x80} },
-{ 0x8dbf, 16, {0x72, 0xaf, 0x41, 0xae, 0x40, 0x12, 0x89, 0xf0, 0x8f, 0x42, 0x80, 0x67, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8dcf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x87, 0x96, 0x8f, 0x42, 0x80, 0x57, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8ddf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x84, 0x1d, 0x8f, 0x42, 0x80, 0x47, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8def, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x50, 0x8f, 0x42, 0x80, 0x37, 0x12, 0x8c, 0x97, 0x8f} },
-{ 0x8dff, 16, {0x42, 0x80, 0x30, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x11, 0xd8, 0x8f} },
-{ 0x8e0f, 16, {0x42, 0x80, 0x20, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x42, 0x8f} },
-{ 0x8e1f, 16, {0x42, 0x80, 0x10, 0xaf, 0x41, 0xae, 0x40, 0x7c, 0x02, 0x7d, 0x4d, 0x7b, 0x40, 0x12, 0x1b, 0x0c} },
-{ 0x8e2f, 5, {0xe4, 0xf5, 0x42, 0xaf, 0x42} },
-{ 0x8e34, 1, {0x22} },
-{ 0x8e35, 8, {0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e} },
-{ 0x8e3d, 16, {0x75, 0x68, 0x01, 0x75, 0x69, 0x3b, 0xe4, 0xf5, 0x67, 0xaf, 0x63, 0x15, 0x63, 0xef, 0x70, 0x03} },
-{ 0x8e4d, 16, {0x02, 0x8e, 0xd3, 0xaf, 0x62, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x61} },
-{ 0x8e5d, 16, {0xae, 0x60, 0xad, 0x5f, 0xac, 0x5e, 0x12, 0x9b, 0x2e, 0xaf, 0x03, 0x8f, 0x66, 0xaf, 0x61, 0xae} },
-{ 0x8e6d, 16, {0x60, 0xad, 0x5f, 0xac, 0x5e, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x62, 0xe4} },
-{ 0x8e7d, 16, {0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
-{ 0x8e8d, 16, {0x12, 0x9b, 0x2e, 0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e, 0xe5, 0x66, 0x24, 0x30, 0xf5} },
-{ 0x8e9d, 16, {0x66, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x66, 0xf5, 0x66, 0x05, 0x69, 0xe5, 0x69} },
-{ 0x8ead, 16, {0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x69, 0xe5} },
-{ 0x8ebd, 16, {0x69, 0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x66, 0xf0, 0x05} },
-{ 0x8ecd, 16, {0x67, 0x05, 0x67, 0x02, 0x8e, 0x46, 0xe5, 0x69, 0x15, 0x69, 0x70, 0x02, 0x15, 0x68, 0xaf, 0x67} },
-{ 0x8edd, 16, {0x15, 0x67, 0xef, 0x60, 0x23, 0xe5, 0x69, 0x15, 0x69, 0xae, 0x68, 0x70, 0x02, 0x15, 0x68, 0xf5} },
-{ 0x8eed, 16, {0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x65, 0xe5, 0x65, 0xac, 0x64, 0x70, 0x02, 0x05, 0x64, 0x14} },
-{ 0x8efd, 8, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
-{ 0x8f05, 1, {0x22} },
-{ 0x8f06, 16, {0xe4, 0x90, 0x01, 0x67, 0xf0, 0x7e, 0x01, 0x7f, 0x68, 0x90, 0x01, 0x5c, 0xee, 0xf0, 0xa3, 0xef} },
-{ 0x8f16, 10, {0xf0, 0x90, 0x01, 0x60, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x8f20, 16, {0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0x67, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
-{ 0x8f30, 16, {0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
-{ 0x8f40, 16, {0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0x60, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8f50, 16, {0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
-{ 0x8f60, 16, {0xeb, 0xf0, 0x90, 0x01, 0x60, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8f70, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x60, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8f80, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8f90, 1, {0x22} },
-{ 0x8f91, 16, {0x90, 0x01, 0x67, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0x5c, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8fa1, 16, {0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
-{ 0x8fb1, 16, {0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
-{ 0x8fc1, 16, {0x9a, 0x1f, 0x90, 0x01, 0x5c, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8fd1, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x5c, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8fe1, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8ff1, 1, {0x22} },
-{ 0x8ff2, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x63, 0x7b, 0x75, 0x64} },
-{ 0x9002, 16, {0x80, 0xe5, 0x64, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x63, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x65, 0xf5} },
-{ 0x9012, 16, {0x66, 0x89, 0x67, 0xfe, 0x12, 0x8f, 0x91, 0xef, 0x60, 0x3b, 0xab, 0x65, 0xaa, 0x66, 0xa9, 0x67} },
-{ 0x9022, 16, {0x12, 0x9a, 0x48, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
-{ 0x9032, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
-{ 0x9042, 16, {0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x9052, 5, {0x74, 0x04, 0xf0, 0xd2, 0xaf} },
-{ 0x9057, 1, {0x22} },
-{ 0x9058, 16, {0x12, 0x8f, 0xf2, 0xe4, 0xf5, 0x5e, 0x74, 0x36, 0x25, 0x5e, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x5f} },
-{ 0x9068, 16, {0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x5f, 0xff, 0xc4} },
-{ 0x9078, 16, {0x54, 0x0f, 0xf5, 0x60, 0x60, 0x22, 0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
-{ 0x9088, 16, {0x83, 0xe5, 0x5f, 0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0xe5, 0x5f, 0x45, 0x60, 0xfb, 0x12, 0x8f, 0x20} },
-{ 0x9098, 16, {0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40} },
-{ 0x90a8, 16, {0xb5, 0x12, 0x8f, 0xf2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8} },
-{ 0x90b8, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x5e} },
-{ 0x90c8, 16, {0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
-{ 0x90d8, 16, {0x16, 0xaf, 0x5e, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2} },
-{ 0x90e8, 16, {0x80, 0xef, 0xe5, 0x5f, 0xf4, 0x52, 0x3a, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
-{ 0x90f8, 16, {0x90, 0x02, 0x9e, 0xe0, 0x60, 0x03, 0x02, 0x91, 0xc5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
-{ 0x9108, 16, {0x11, 0x8e, 0x61, 0x8f, 0x62, 0xc3, 0xe5, 0x61, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
-{ 0x9118, 16, {0x5b, 0xe0, 0x65, 0x62, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8, 0x07} },
-{ 0x9128, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01, 0x5b, 0xe0, 0x55, 0x5f, 0x60} },
-{ 0x9138, 16, {0x14, 0xaf, 0x5e, 0x7d, 0x08, 0xe5, 0x5f, 0x55, 0x62, 0xfb, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05} },
-{ 0x9148, 16, {0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
-{ 0x9158, 16, {0x5b, 0xe5, 0x62, 0xf0, 0xe4, 0xf5, 0x5e, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x5e, 0xf8, 0xe6, 0xf5} },
-{ 0x9168, 16, {0x5f, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x5f, 0x1e, 0xe5, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x02} },
-{ 0x9178, 16, {0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
-{ 0x9188, 16, {0x5e, 0xf8, 0xe6, 0xf5, 0x5f, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x9198, 16, {0xe0, 0x65, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x04, 0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70} },
-{ 0x91a8, 16, {0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x91b8, 16, {0x83, 0xe5, 0x5f, 0xf0, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x8f, 0xf2} },
-{ 0x91c8, 1, {0x22} },
-{ 0x91c9, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x6e, 0x02, 0x92, 0x10} },
-{ 0x91d5, 16, {0x02, 0x05, 0x28, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
-{ 0x91e5, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
-{ 0x91f5, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
-{ 0x9205, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x92, 0x55, 0xe4, 0x7e} },
-{ 0x9215, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
-{ 0x9225, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
-{ 0x9235, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
-{ 0x9245, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
-{ 0x9255, 16, {0x60, 0x24, 0x02, 0x28, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
-{ 0x9265, 16, {0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
-{ 0x9275, 8, {0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
-{ 0x927d, 1, {0x00} },
-{ 0x927e, 11, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
-{ 0x9289, 16, {0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
-{ 0x9299, 16, {0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
-{ 0x92a9, 16, {0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xb5, 0x1e} },
-{ 0x92b9, 10, {0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0x62, 0xee, 0xf0} },
-{ 0x92c3, 9, {0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x92cc, 2, {0xa9, 0x03} },
-{ 0x92ce, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
-{ 0x92de, 16, {0x6c, 0x45, 0x6d, 0xf5, 0x6e, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
-{ 0x92ee, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
-{ 0x92fe, 16, {0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x6e, 0xeb} },
-{ 0x930e, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x6e, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
-{ 0x931e, 16, {0x05, 0x22, 0xe5, 0x6c, 0x5c, 0xfe, 0xe5, 0x6d, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
-{ 0x932e, 16, {0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
-{ 0x933e, 16, {0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x6c, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x6d, 0x22, 0x7f} },
-{ 0x934e, 1, {0x00} },
-{ 0x934f, 1, {0x22} },
-{ 0x9350, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xf5, 0x66, 0xe4, 0x3e, 0xf5, 0x65, 0x75, 0x63, 0x02} },
-{ 0x9360, 16, {0x75, 0x64, 0x4e, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0f, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x9370, 16, {0xe0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0xa3, 0xe0} },
-{ 0x9380, 16, {0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xf0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3} },
-{ 0x9390, 16, {0x74, 0xff, 0xf0, 0xe5, 0x66, 0x24, 0x03, 0xf5, 0x68, 0xe4, 0x35, 0x65, 0xf5, 0x67, 0x85, 0x64} },
-{ 0x93a0, 16, {0x82, 0x85, 0x63, 0x83, 0xe0, 0x14, 0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x98, 0x43, 0x90, 0x93} },
-{ 0x93b0, 16, {0xb5, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x93, 0xd6, 0x02, 0x94, 0x7c, 0x02, 0x95, 0xba, 0x02, 0x95} },
-{ 0x93c0, 16, {0xda, 0x02, 0x95, 0xda, 0x02, 0x96, 0x7f, 0x02, 0x96, 0xbd, 0x02, 0x96, 0xe4, 0x02, 0x97, 0xa6} },
-{ 0x93d0, 16, {0x02, 0x97, 0xda, 0x02, 0x98, 0x0b, 0xe4, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x93e0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xe4, 0xff, 0xe4, 0xfe} },
-{ 0x93f0, 16, {0xef, 0x60, 0x10, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5} },
-{ 0x9400, 16, {0x5f, 0x80, 0x0d, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x5f} },
-{ 0x9410, 16, {0xe5, 0x62, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe5, 0x5f, 0xf0, 0xe0, 0xf5} },
-{ 0x9420, 16, {0x60, 0x65, 0x5f, 0x60, 0x3d, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5} },
-{ 0x9430, 16, {0x5e, 0x04, 0xfd, 0x05, 0x68, 0xe5, 0x68, 0xaa, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82} },
-{ 0x9440, 16, {0x8a, 0x83, 0xed, 0xf0, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9450, 16, {0x82, 0x8c, 0x83, 0xe5, 0x5f, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02} },
-{ 0x9460, 16, {0x98, 0x4e, 0x0e, 0xee, 0x64, 0x24, 0x70, 0x88, 0x0f, 0xef, 0x64, 0x02, 0x70, 0x80, 0x05, 0x5e} },
-{ 0x9470, 16, {0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03, 0x02, 0x93, 0xd9, 0x02, 0x98, 0x4e, 0x7e, 0x20, 0x7f, 0x00} },
-{ 0x9480, 16, {0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9490, 16, {0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5} },
-{ 0x94a0, 16, {0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04, 0x74, 0x92, 0xf0, 0xa3, 0x74, 0x7e, 0xf0} },
-{ 0x94b0, 16, {0xe4, 0xf5, 0x60, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xf5, 0x5e, 0xaf} },
-{ 0x94c0, 16, {0x5e, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01} },
-{ 0x94d0, 16, {0x62, 0xf0, 0x90, 0x01, 0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x94e0, 16, {0x83, 0xa3, 0x74, 0x02, 0xf0, 0x90, 0x01, 0x62, 0xe0, 0x65, 0x5f, 0x70, 0x39, 0x90, 0x01, 0x5e} },
-{ 0x94f0, 16, {0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xee, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0} },
-{ 0x9500, 16, {0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9510, 16, {0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
-{ 0x9520, 16, {0x01, 0x62, 0xf0, 0x75, 0x60, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xff, 0x60, 0x3c, 0x85, 0x66, 0x82} },
-{ 0x9530, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xfe, 0x05, 0x68, 0xe5, 0x68, 0xac} },
-{ 0x9540, 16, {0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x68, 0xe5, 0x68} },
-{ 0x9550, 16, {0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82} },
-{ 0x9560, 16, {0x85, 0x67, 0x83, 0xe5, 0x5f, 0xf0, 0x75, 0x60, 0xff, 0xe5, 0x60, 0x70, 0x16, 0x74, 0x08, 0x25} },
-{ 0x9570, 16, {0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03} },
-{ 0x9580, 16, {0x02, 0x94, 0xbf, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e} },
-{ 0x9590, 16, {0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4} },
-{ 0x95a0, 16, {0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04} },
-{ 0x95b0, 16, {0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12, 0xf0, 0x02, 0x98, 0x4e, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x95c0, 16, {0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90} },
-{ 0x95d0, 16, {0x02, 0x95, 0xf0, 0x90, 0x01, 0x62, 0xf0, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0x74, 0x03, 0xf0} },
-{ 0x95e0, 16, {0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0} },
-{ 0x95f0, 16, {0xb5, 0x07, 0x1e, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x85, 0x66, 0x82} },
-{ 0x9600, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xf5} },
-{ 0x9610, 16, {0x60, 0xe5, 0x60, 0x60, 0x03, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0x74, 0x96, 0xf0} },
-{ 0x9620, 16, {0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3} },
-{ 0x9630, 16, {0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0} },
-{ 0x9640, 16, {0x55, 0x60, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x5f, 0x85, 0x64, 0x82, 0x85} },
-{ 0x9650, 16, {0x63, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x5f, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00} },
-{ 0x9660, 16, {0x8f, 0x5f, 0xe5, 0x5f, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3} },
-{ 0x9670, 16, {0xa3, 0xe4, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x7e} },
-{ 0x9680, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9690, 16, {0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x96a0, 16, {0x62, 0x82, 0x85, 0x61, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x96b0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x98, 0x4e, 0xc2, 0x04, 0x7e} },
-{ 0x96c0, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
-{ 0x96d0, 16, {0x35, 0x61, 0xf5, 0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81} },
-{ 0x96e0, 16, {0xe0, 0x02, 0x98, 0x4e, 0xe4, 0xf5, 0x60, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x96f0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xfe, 0xe4, 0xfd, 0x12} },
-{ 0x9700, 16, {0x81, 0xe0, 0xe5, 0x62, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe0, 0x54, 0xfc} },
-{ 0x9710, 16, {0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc} },
-{ 0x9720, 16, {0x8f, 0x60, 0xe5, 0x60, 0x70, 0x11, 0xaf, 0x5e, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x6c, 0x10, 0x75} },
-{ 0x9730, 16, {0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf, 0x5e, 0x7d, 0x01, 0xfb} },
-{ 0x9740, 16, {0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf} },
-{ 0x9750, 16, {0x5e, 0x7d, 0x02, 0xfb, 0x75, 0x6c, 0x10, 0x75, 0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xaf} },
-{ 0x9760, 16, {0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0xe5, 0x60, 0x60, 0x2b, 0x85, 0x66, 0x82, 0x85} },
-{ 0x9770, 16, {0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67} },
-{ 0x9780, 16, {0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67} },
-{ 0x9790, 16, {0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x50, 0x03} },
-{ 0x97a0, 16, {0x02, 0x96, 0xe9, 0x02, 0x98, 0x4e, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x97b0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x98, 0xf0, 0xa3, 0x74, 0x6d, 0xf0, 0x7e} },
-{ 0x97c0, 16, {0x02, 0x7f, 0xd3, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66} },
-{ 0x97d0, 16, {0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x74, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3} },
-{ 0x97e0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x67, 0xf0, 0xa3} },
-{ 0x97f0, 16, {0xe5, 0x68, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x4f, 0x85} },
-{ 0x9800, 16, {0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x43, 0xe4, 0x90, 0x02, 0xd3, 0xf0} },
-{ 0x9810, 16, {0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x64, 0x24, 0x02} },
-{ 0x9820, 16, {0x90, 0x02, 0xda, 0xf0, 0xe4, 0x35, 0x63, 0x90, 0x02, 0xd9, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12} },
-{ 0x9830, 16, {0x80, 0x00, 0xef, 0x64, 0x08, 0x60, 0x17, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4} },
-{ 0x9840, 16, {0xf0, 0x80, 0x0b, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0x74, 0x01, 0xf0, 0x90, 0x01} },
-{ 0x9850, 16, {0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
-{ 0x9860, 12, {0xf6, 0x90, 0x7f, 0xc3, 0x74, 0x24, 0xf0, 0xe4, 0x90, 0x02, 0x4d, 0xf0} },
-{ 0x986c, 1, {0x22} },
-{ 0x986d, 16, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
-{ 0x987d, 16, {0xe4, 0xfd, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x05, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce} },
-{ 0x988d, 16, {0xd8, 0xf9, 0xff, 0xe5, 0x3b, 0xfb, 0xe4, 0xef, 0x5b, 0x70, 0x03, 0x02, 0x99, 0x45, 0xed, 0x75} },
-{ 0x989d, 16, {0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xfe, 0xf5, 0x83, 0xe5} },
-{ 0x98ad, 16, {0x82, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x60} },
-{ 0x98bd, 16, {0x03, 0x02, 0x99, 0x45, 0xef, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0xfc, 0x74} },
-{ 0x98cd, 16, {0x36, 0x2d, 0xf8, 0xec, 0xf6, 0x30, 0xe5, 0x70, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02} },
-{ 0x98dd, 16, {0xf5, 0x83, 0xe0, 0x60, 0x63, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x98ed, 16, {0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8f, 0x82} },
-{ 0x98fd, 16, {0x8e, 0x83, 0xf0, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0} },
-{ 0x990d, 16, {0x70, 0x36, 0xed, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0} },
-{ 0x991d, 16, {0xed, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82} },
-{ 0x992d, 16, {0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x993d, 16, {0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x0d, 0xed, 0x64, 0x04, 0x60, 0x03, 0x02, 0x98} },
-{ 0x994d, 1, {0x7f} },
-{ 0x994e, 1, {0x22} },
-{ 0x994f, 16, {0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
-{ 0x995f, 16, {0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
-{ 0x996f, 16, {0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
-{ 0x997f, 16, {0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
-{ 0x998f, 16, {0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
-{ 0x999f, 16, {0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
-{ 0x99af, 16, {0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
-{ 0x99bf, 16, {0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
-{ 0x99cf, 16, {0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
-{ 0x99df, 16, {0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
-{ 0x99ef, 16, {0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
-{ 0x99ff, 16, {0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
-{ 0x9a0f, 16, {0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
-{ 0x9a1f, 16, {0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
-{ 0x9a2f, 16, {0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
-{ 0x9a3f, 9, {0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x99, 0x9f, 0x73} },
-{ 0x9a48, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
-{ 0x9a58, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a61, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
-{ 0x9a71, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
-{ 0x9a81, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a8e, 16, {0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
-{ 0x9a9e, 6, {0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
-{ 0x9aa4, 16, {0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
-{ 0x9ab4, 6, {0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
-{ 0x9aba, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
-{ 0x9aca, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
-{ 0x9ada, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
-{ 0x9aea, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
-{ 0x9af2, 16, {0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
-{ 0x9b02, 16, {0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
-{ 0x9b12, 16, {0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
-{ 0x9b22, 16, {0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
-{ 0x9b32, 16, {0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
-{ 0x9b42, 16, {0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
-{ 0x9b52, 16, {0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
-{ 0x9b62, 16, {0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
-{ 0x9b72, 16, {0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
-{ 0x9b82, 16, {0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
-{ 0x9b92, 16, {0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
-{ 0x9ba2, 16, {0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
-{ 0x9bb2, 14, {0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
-{ 0x9bc0, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
-{ 0x9bd0, 1, {0x22} },
-{ 0x9bd1, 16, {0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
-{ 0x9be1, 3, {0xd8, 0xf1, 0x22} },
-{ 0x9be4, 16, {0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
-{ 0x9bf4, 7, {0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
-{ 0x9bfb, 12, {0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x9c07, 16, {0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0x12} },
-{ 0x9c17, 16, {0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
-{ 0x9c27, 16, {0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
-{ 0x9c37, 1, {0x22} },
+{ 0x81e0, 2, {0xae, 0x07} },
+{ 0x81e2, 16, {0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x81f2, 16, {0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
+{ 0x8202, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
+{ 0x8212, 16, {0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
+{ 0x8222, 14, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
+{ 0x8230, 1, {0x22} },
+{ 0x8231, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
+{ 0x8241, 15, {0x53, 0x91, 0x7f, 0x90, 0x01, 0xc4, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x8250, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
+{ 0x8260, 16, {0x83, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x5e, 0x74, 0xbf} },
+{ 0x8270, 16, {0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x8280, 16, {0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xf0, 0xf9, 0xed, 0x60, 0x1d, 0x74, 0x01} },
+{ 0x8290, 16, {0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4} },
+{ 0x82a0, 16, {0xef, 0x55, 0x3b, 0x60, 0x04, 0x79, 0x09, 0x80, 0x02, 0x79, 0x0d, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x82b0, 16, {0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54, 0xef, 0xf0, 0x8b} },
+{ 0x82c0, 16, {0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5e, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e} },
+{ 0x82d0, 4, {0x83, 0xa3, 0xe9, 0xf0} },
+{ 0x82d4, 1, {0x22} },
+{ 0x82d5, 4, {0x8f, 0x5e, 0x8d, 0x5f} },
+{ 0x82d9, 16, {0xe4, 0xf5, 0x60, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x82e9, 16, {0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x82f9, 16, {0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50} },
+{ 0x8309, 16, {0x3c, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83} },
+{ 0x8319, 16, {0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
+{ 0x8329, 16, {0x00, 0xc3, 0x12, 0x9c, 0xea, 0x40, 0x0c, 0x75, 0x60, 0x40, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76} },
+{ 0x8339, 16, {0x10, 0x80, 0x0a, 0x75, 0x60, 0x80, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76, 0x38, 0xe5, 0x60, 0x45} },
+{ 0x8349, 16, {0x5f, 0x44, 0x01, 0xff, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x8359, 5, {0x20, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x835e, 1, {0x22} },
+{ 0x835f, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x836f, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x55, 0x8f, 0x56, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc6, 0xf5} },
+{ 0x837f, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc7} },
+{ 0x838f, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x25, 0x54, 0xf8, 0xe4, 0xf6} },
+{ 0x839f, 16, {0xe5, 0x56, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf} },
+{ 0x83af, 16, {0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xaf, 0x54, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x85, 0x56, 0x82} },
+{ 0x83bf, 16, {0x85, 0x55, 0x83, 0xa3, 0xa3, 0xe0, 0x20, 0xe0, 0x22, 0xe0, 0xff, 0xe5, 0x56, 0x24, 0x05, 0xf5} },
+{ 0x83cf, 16, {0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0xe5, 0x56, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x55} },
+{ 0x83df, 16, {0xf5, 0x83, 0xe0, 0xff, 0xaf, 0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x74, 0xf8, 0x25, 0x54, 0xf5} },
+{ 0x83ef, 16, {0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c} },
+{ 0x83ff, 16, {0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe} },
+{ 0x840f, 16, {0xe5, 0x54, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3} },
+{ 0x841f, 16, {0xef, 0xf0, 0xaf, 0x54, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42} },
+{ 0x842f, 3, {0x30, 0x7f, 0x00} },
+{ 0x8432, 1, {0x22} },
+{ 0x8433, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0xff, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x74, 0xf8} },
+{ 0x8443, 16, {0x25, 0x54, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x75, 0xf0, 0x08} },
+{ 0x8453, 16, {0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x56, 0x8f, 0x57, 0xf5, 0x83} },
+{ 0x8463, 16, {0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x8473, 16, {0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xe5, 0x57, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x56, 0xf5} },
+{ 0x8483, 16, {0x83, 0xe0, 0x30, 0xe0, 0x09, 0x85, 0x57, 0x82, 0x85, 0x56, 0x83, 0xe0, 0xf5, 0x55, 0xaf, 0x54} },
+{ 0x8493, 16, {0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x54} },
+{ 0x84a3, 16, {0x25, 0xe0, 0x24, 0xc6, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5} },
+{ 0x84b3, 16, {0x54, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x7f, 0x00} },
+{ 0x84c3, 1, {0x22} },
+{ 0x84c4, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x84c8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x56, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
+{ 0x84d8, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x55, 0x82, 0x8e, 0x83, 0xa3} },
+{ 0x84e8, 16, {0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x56, 0x7d, 0x02, 0x12, 0x82, 0xd5, 0x85, 0x55, 0x82, 0x85, 0x54} },
+{ 0x84f8, 15, {0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x56, 0x7d, 0x04, 0x12, 0x82, 0xd5, 0x7f, 0x00} },
+{ 0x8507, 1, {0x22} },
+{ 0x8508, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
+{ 0x8518, 16, {0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8528, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
+{ 0x8538, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
+{ 0x8548, 16, {0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
+{ 0x8558, 16, {0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
+{ 0x8568, 16, {0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
+{ 0x8578, 16, {0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8588, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
+{ 0x8598, 3, {0x83, 0xf0, 0x22} },
+{ 0x859b, 16, {0x79, 0x0d, 0x8e, 0x54, 0x8f, 0x55, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x85ab, 16, {0xf4, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xaf, 0x82, 0xfe, 0xad, 0x01, 0x19, 0xed, 0x60, 0x24, 0x0f} },
+{ 0x85bb, 16, {0xef, 0xac, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x55, 0xe5} },
+{ 0x85cb, 16, {0x55, 0xaa, 0x54, 0x70, 0x02, 0x05, 0x54, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0x6d, 0x60, 0xd9} },
+{ 0x85db, 5, {0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x85e0, 1, {0x22} },
+{ 0x85e1, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x85e5, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x85f5, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x5c, 0x8f, 0x5d, 0xaa, 0x06, 0xa9, 0x55, 0x7b, 0x01, 0xc0} },
+{ 0x8605, 16, {0x03, 0xc0, 0x01, 0xe5, 0x5b, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x01, 0xf9, 0x74, 0x03, 0x35, 0xf0} },
+{ 0x8615, 16, {0xa8, 0x01, 0xfc, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9b, 0x49} },
+{ 0x8625, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8635, 16, {0xe0, 0xff, 0x7b, 0x08, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xd3, 0x12, 0x9c, 0xea, 0x40, 0x10} },
+{ 0x8645, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x00, 0x08, 0x80, 0x2e} },
+{ 0x8655, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8665, 16, {0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x08, 0x79, 0x07, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50, 0x0e} },
+{ 0x8675, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x07, 0x08, 0x00, 0x85, 0x55} },
+{ 0x8685, 16, {0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x8695, 16, {0x7f, 0x00, 0x7e, 0x50, 0x7d, 0x46, 0x7c, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d} },
+{ 0x86a5, 16, {0x57, 0x8c, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0x12, 0x9c, 0x58, 0xaf, 0x03} },
+{ 0x86b5, 16, {0x8f, 0x5a, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x86c5, 16, {0x78, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d, 0x57, 0x8c, 0x56, 0xe5, 0x5a, 0xc3} },
+{ 0x86d5, 16, {0x94, 0x05, 0x40, 0x15, 0xe5, 0x59, 0x24, 0x01, 0xf5, 0x59, 0xe4, 0x35, 0x58, 0xf5, 0x58, 0xe4} },
+{ 0x86e5, 16, {0x35, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3} },
+{ 0x86f5, 16, {0xe4, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8705, 16, {0x5d, 0x82, 0x85, 0x5c, 0x83, 0xe5, 0x59, 0xf0, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56} },
+{ 0x8715, 16, {0x78, 0x08, 0x12, 0x9c, 0xfb, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x5d} },
+{ 0x8725, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x5a, 0xe5, 0x55} },
+{ 0x8735, 16, {0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x5a} },
+{ 0x8745, 16, {0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05, 0x43, 0x5a, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03} },
+{ 0x8755, 16, {0x43, 0x5a, 0x02, 0xe5, 0x55, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x8765, 16, {0x30, 0xe3, 0x03, 0x43, 0x5a, 0x80, 0xef, 0x30, 0xe7, 0x12, 0x43, 0x5a, 0x40, 0xe5, 0x5d, 0x24} },
+{ 0x8775, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x55, 0x24, 0x0b} },
+{ 0x8785, 16, {0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x23, 0xaf} },
+{ 0x8795, 16, {0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x5d} },
+{ 0x87a5, 16, {0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0xe4, 0xf5, 0x5a} },
+{ 0x87b5, 16, {0x80, 0x10, 0xaf, 0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4} },
+{ 0x87c5, 16, {0x52, 0x3b, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x85, 0x5d} },
+{ 0x87d5, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5} },
+{ 0x87e5, 16, {0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x87f5, 16, {0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83} },
+{ 0x8805, 16, {0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5} },
+{ 0x8815, 16, {0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x06} },
+{ 0x8825, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4} },
+{ 0x8835, 16, {0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5} },
+{ 0x8845, 16, {0x83, 0xef, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x85, 0x5d} },
+{ 0x8855, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xf0, 0xaf, 0x5b, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x75, 0x5a} },
+{ 0x8865, 16, {0x08, 0xe5, 0x55, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43} },
+{ 0x8875, 16, {0x5a, 0x10, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x54, 0x03} },
+{ 0x8885, 16, {0x45, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x14} },
+{ 0x8895, 16, {0xff, 0x25, 0xe0, 0x25, 0xe0, 0xff, 0xe5, 0x55, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5} },
+{ 0x88a5, 16, {0x83, 0xe0, 0x24, 0xfb, 0x4f, 0xf5, 0x5a, 0xe5, 0x55, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x54} },
+{ 0x88b5, 16, {0xf5, 0x83, 0xe0, 0x24, 0xd0, 0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a} },
+{ 0x88c5, 16, {0x70, 0x12, 0x43, 0x5a, 0x18, 0x80, 0x0d, 0x43, 0x5a, 0x08, 0x80, 0x08, 0x43, 0x5a, 0x38, 0x80} },
+{ 0x88d5, 16, {0x03, 0x43, 0x5a, 0x28, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5a, 0xf0} },
+{ 0x88e5, 9, {0xaf, 0x5b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x7f, 0x00} },
+{ 0x88ee, 1, {0x22} },
+{ 0x88ef, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4} },
+{ 0x88ff, 16, {0x34, 0x20, 0xad, 0x82, 0xfc, 0x90, 0x01, 0x2c, 0x74, 0x08, 0xf0, 0xef, 0x04, 0xa3, 0xf0, 0xe4} },
+{ 0x890f, 16, {0xa3, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5} },
+{ 0x891f, 16, {0x83, 0xe0, 0x90, 0x01, 0x2f, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0xf5, 0x82} },
+{ 0x892f, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x90, 0x01, 0x30, 0xf0, 0x74, 0x2c, 0x2f, 0xf8} },
+{ 0x893f, 16, {0xe6, 0xa3, 0xf0, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x54} },
+{ 0x894f, 16, {0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x54, 0x5f} },
+{ 0x895f, 16, {0x90, 0x01, 0x32, 0xf0, 0x7e, 0x01, 0x7f, 0x2c, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e} },
+{ 0x896f, 11, {0x00, 0x75, 0x5d, 0x00, 0x7d, 0x07, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x897a, 1, {0x22} },
+{ 0x897b, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x898b, 16, {0xaf, 0x82, 0xfe, 0x90, 0x01, 0x33, 0x74, 0x0a, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x24} },
+{ 0x899b, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x90, 0x01, 0x34, 0xf0, 0x7e, 0x01, 0x7f} },
+{ 0x89ab, 16, {0x33, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x02, 0x12} },
+{ 0x89bb, 4, {0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x89bf, 1, {0x22} },
+{ 0x89c0, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x89d0, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x89e0, 16, {0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x89f0, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
+{ 0x89fb, 1, {0x22} },
+{ 0x89fc, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a0c, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x8a1c, 16, {0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x8a2c, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
+{ 0x8a37, 1, {0x22} },
+{ 0x8a38, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a48, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x8a58, 16, {0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
+{ 0x8a68, 7, {0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
+{ 0x8a6f, 1, {0x22} },
+{ 0x8a70, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8a74, 16, {0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x58, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x8a84, 16, {0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
+{ 0x8a94, 16, {0x56, 0x7e, 0x75, 0x57, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x56, 0x7e, 0x75, 0x57} },
+{ 0x8aa4, 16, {0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x80, 0x80, 0x0a, 0x7e} },
+{ 0x8ab4, 16, {0x7d, 0x7f, 0x00, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x00, 0xe5, 0x58, 0x70, 0x20, 0x85, 0x57, 0x82} },
+{ 0x8ac4, 16, {0x85, 0x56, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8ad4, 16, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x4d, 0xe5, 0x55, 0x24} },
+{ 0x8ae4, 16, {0x02, 0xff, 0xe4, 0x35, 0x54, 0xfe, 0xe5, 0x58, 0x60, 0x23, 0x0f, 0xef, 0xac, 0x06, 0x70, 0x01} },
+{ 0x8af4, 16, {0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x57, 0xe5, 0x57, 0xaa, 0x56, 0x70, 0x02} },
+{ 0x8b04, 16, {0x05, 0x56, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x15, 0x58, 0x80, 0xd9, 0x85, 0x55, 0x82} },
+{ 0x8b14, 16, {0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8b24, 12, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
+{ 0x8b30, 1, {0x22} },
+{ 0x8b31, 16, {0xef, 0x24, 0x05, 0xf5, 0x55, 0xe4, 0x3e, 0xf5, 0x54, 0x90, 0x01, 0x35, 0x74, 0x07, 0xf0, 0x90} },
+{ 0x8b41, 16, {0x01, 0x7a, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x36, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8b51, 16, {0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x56, 0xf5, 0x57, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8b61, 16, {0xe0, 0x24, 0x9e, 0x60, 0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x12} },
+{ 0x8b71, 16, {0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x5e, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe} },
+{ 0x8b81, 16, {0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x59, 0x74, 0x01, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59} },
+{ 0x8b91, 16, {0x94, 0x40, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5} },
+{ 0x8ba1, 16, {0x57, 0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x50, 0x03, 0x02, 0x8c, 0x61, 0xae, 0x58, 0xaf, 0x59} },
+{ 0x8bb1, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e} },
+{ 0x8bc1, 16, {0x56, 0xf5, 0x57, 0x02, 0x8c, 0x61, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8bd1, 16, {0xe0, 0xff, 0xc3, 0x74, 0x30, 0x9f, 0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59, 0x94} },
+{ 0x8be1, 16, {0x10, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x10, 0xd3, 0xe5, 0x57} },
+{ 0x8bf1, 16, {0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x40, 0x68, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85} },
+{ 0x8c01, 16, {0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x80} },
+{ 0x8c11, 16, {0x4f, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f} },
+{ 0x8c21, 16, {0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0x45, 0x59, 0x60, 0x0b, 0xd3, 0xe5, 0x59, 0x94, 0x40, 0xe5} },
+{ 0x8c31, 16, {0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5, 0x57, 0x95, 0x59} },
+{ 0x8c41, 16, {0xe5, 0x56, 0x95, 0x58, 0x40, 0x17, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8c51, 16, {0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x7f, 0x01, 0x22} },
+{ 0x8c61, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8d, 0x21, 0x24, 0xf9} },
+{ 0x8c71, 16, {0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8d, 0x71, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8d, 0xb5} },
+{ 0x8c81, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
+{ 0x8c91, 16, {0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57} },
+{ 0x8ca1, 16, {0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xe0} },
+{ 0x8cb1, 16, {0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b} },
+{ 0x8cc1, 16, {0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8cd1, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8d} },
+{ 0x8ce1, 16, {0xb5, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x76} },
+{ 0x8cf1, 16, {0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02} },
+{ 0x8d01, 16, {0x8d, 0xb5, 0x90, 0x01, 0x76, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d11, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
+{ 0x8d21, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
+{ 0x8d31, 16, {0x94, 0x00, 0x50, 0x03, 0x02, 0x8d, 0xb5, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
+{ 0x8d41, 16, {0x90, 0x01, 0x77, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e} },
+{ 0x8d51, 16, {0x60, 0x62, 0x90, 0x01, 0x77, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d61, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
+{ 0x8d71, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x78, 0xcf, 0xf0} },
+{ 0x8d81, 16, {0xa3, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x60, 0x24} },
+{ 0x8d91, 16, {0x90, 0x01, 0x78, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
+{ 0x8da1, 16, {0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x8db1, 16, {0xef, 0xf0, 0x80, 0xcf, 0x7e, 0x01, 0x7f, 0x35, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3} },
+{ 0x8dc1, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x04, 0xfd, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75} },
+{ 0x8dd1, 7, {0x5d, 0x00, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8dd8, 1, {0x22} },
+{ 0x8dd9, 16, {0x8e, 0x61, 0x8f, 0x62, 0x8c, 0x63, 0x8d, 0x64, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x62} },
+{ 0x8de9, 16, {0xe5, 0x62, 0xae, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
+{ 0x8df9, 16, {0x64, 0xe5, 0x64, 0xac, 0x63, 0x70, 0x02, 0x05, 0x63, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x8e09, 3, {0x80, 0xd6, 0x22} },
+{ 0x8e0c, 16, {0x8d, 0x5c, 0xab, 0x07, 0xaa, 0x06, 0xaf, 0x60, 0xae, 0x5f, 0xad, 0x5e, 0xac, 0x5d, 0xec, 0x4d} },
+{ 0x8e1c, 16, {0x4e, 0x4f, 0x60, 0x1c, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x1c, 0x7f, 0xff, 0x7e, 0xff, 0x7d} },
+{ 0x8e2c, 16, {0xff, 0x7c, 0xff, 0x78, 0x5d, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0x09, 0x80, 0xe4} },
+{ 0x8e3c, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0xf9, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x16, 0xaf, 0x03} },
+{ 0x8e4c, 16, {0xae, 0x02, 0x7c, 0x7b, 0x7d, 0x80, 0xab, 0x5c, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xc3, 0xe5, 0x5c} },
+{ 0x8e5c, 7, {0xf0, 0x7f, 0x01, 0x22, 0x7f, 0x00, 0x22} },
+{ 0x8e63, 16, {0x90, 0x01, 0x84, 0x74, 0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f} },
+{ 0x8e73, 16, {0x90, 0x01, 0x85, 0xf0, 0x90, 0x11, 0xfd, 0xe4, 0x93, 0x90, 0x01, 0x86, 0xf0, 0x90, 0x11, 0xfe} },
+{ 0x8e83, 16, {0xe4, 0x93, 0x90, 0x01, 0x87, 0xf0, 0xe4, 0x90, 0x01, 0x7c, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x8e93, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x88, 0xf0, 0x7e} },
+{ 0x8ea3, 16, {0x01, 0x7f, 0x7c, 0x12, 0x19, 0xc1, 0x7e, 0x01, 0x7f, 0x84, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x8eb3, 13, {0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x14, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8ec0, 1, {0x22} },
+{ 0x8ec1, 4, {0x8e, 0x4b, 0x8f, 0x4c} },
+{ 0x8ec5, 16, {0x85, 0x4b, 0x4e, 0x85, 0x4c, 0x4f, 0xe5, 0x4f, 0x24, 0x01, 0xf5, 0x53, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x8ed5, 16, {0x52, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0x14, 0xb4, 0x0f, 0x00, 0x40, 0x03, 0x02, 0x8f} },
+{ 0x8ee5, 16, {0xd6, 0x90, 0x8e, 0xed, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8f, 0x1a, 0x02, 0x8f, 0x26, 0x02, 0x8f} },
+{ 0x8ef5, 16, {0x32, 0x02, 0x8f, 0x5c, 0x02, 0x8f, 0x67, 0x02, 0x8f, 0x72, 0x02, 0x8f, 0x7d, 0x02, 0x8f, 0x88} },
+{ 0x8f05, 16, {0x02, 0x8f, 0x93, 0x02, 0x8f, 0x9e, 0x02, 0x8f, 0xa9, 0x02, 0x8f, 0xb0, 0x02, 0x8f, 0xd6, 0x02} },
+{ 0x8f15, 16, {0x8f, 0xbb, 0x02, 0x8f, 0xc6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x83, 0x5f, 0x8f, 0x4d, 0x02, 0x8f} },
+{ 0x8f25, 16, {0xd6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x84, 0x33, 0x8f, 0x4d, 0x02, 0x8f, 0xd6, 0x85, 0x52, 0x50} },
+{ 0x8f35, 16, {0x85, 0x53, 0x51, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xfe, 0x12, 0x85, 0x08, 0xaf} },
+{ 0x8f45, 16, {0x51, 0xae, 0x50, 0x12, 0x85, 0x9b, 0xef, 0x70, 0x03, 0x02, 0x8f, 0xd6, 0xaf, 0x51, 0xae, 0x50} },
+{ 0x8f55, 16, {0x12, 0x85, 0xe1, 0x8f, 0x4d, 0x80, 0x7a, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xc0, 0x8f, 0x4d} },
+{ 0x8f65, 16, {0x80, 0x6f, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xfc, 0x8f, 0x4d, 0x80, 0x64, 0xaf, 0x53, 0xae} },
+{ 0x8f75, 16, {0x52, 0x12, 0x8a, 0x38, 0x8f, 0x4d, 0x80, 0x59, 0xaf, 0x4c, 0xae, 0x4b, 0x12, 0x8b, 0x31, 0x8f} },
+{ 0x8f85, 16, {0x4d, 0x80, 0x4e, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x88, 0xef, 0x8f, 0x4d, 0x80, 0x43, 0xaf, 0x53} },
+{ 0x8f95, 16, {0xae, 0x52, 0x12, 0x84, 0xc4, 0x8f, 0x4d, 0x80, 0x38, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0x7b} },
+{ 0x8fa5, 16, {0x8f, 0x4d, 0x80, 0x2d, 0x12, 0x8e, 0x63, 0x8f, 0x4d, 0x80, 0x26, 0xaf, 0x53, 0xae, 0x52, 0x12} },
+{ 0x8fb5, 16, {0x11, 0xe5, 0x8f, 0x4d, 0x80, 0x1b, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x8a, 0x70, 0x8f, 0x4d, 0x80} },
+{ 0x8fc5, 16, {0x10, 0xaf, 0x4c, 0xae, 0x4b, 0x7c, 0x02, 0x7d, 0xaf, 0x7b, 0x40, 0x12, 0x8d, 0xd9, 0xe4, 0xf5} },
+{ 0x8fd5, 16, {0x4d, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0xff, 0x14, 0x24, 0xfa, 0x50, 0x04, 0x24, 0xfe} },
+{ 0x8fe5, 16, {0x70, 0x2b, 0x90, 0x01, 0x98, 0x74, 0x10, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x8ff5, 16, {0x83, 0xe0, 0x90, 0x01, 0x9a, 0xf0, 0x7e, 0x01, 0x7f, 0x98, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x9005, 15, {0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x03, 0x12, 0x8e, 0x0c, 0x8f, 0x4d, 0xaf, 0x4d} },
+{ 0x9014, 1, {0x22} },
+{ 0x9015, 8, {0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b} },
+{ 0x901d, 16, {0x75, 0x55, 0x01, 0x75, 0x56, 0x9c, 0xe4, 0xf5, 0x54, 0xaf, 0x50, 0x15, 0x50, 0xef, 0x70, 0x03} },
+{ 0x902d, 16, {0x02, 0x90, 0xb3, 0xaf, 0x4f, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x4e} },
+{ 0x903d, 16, {0xae, 0x4d, 0xad, 0x4c, 0xac, 0x4b, 0x12, 0x9c, 0x58, 0xaf, 0x03, 0x8f, 0x53, 0xaf, 0x4e, 0xae} },
+{ 0x904d, 16, {0x4d, 0xad, 0x4c, 0xac, 0x4b, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x4f, 0xe4} },
+{ 0x905d, 16, {0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
+{ 0x906d, 16, {0x12, 0x9c, 0x58, 0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b, 0xe5, 0x53, 0x24, 0x30, 0xf5} },
+{ 0x907d, 16, {0x53, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x53, 0xf5, 0x53, 0x05, 0x56, 0xe5, 0x56} },
+{ 0x908d, 16, {0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x56, 0xe5} },
+{ 0x909d, 16, {0x56, 0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x53, 0xf0, 0x05} },
+{ 0x90ad, 16, {0x54, 0x05, 0x54, 0x02, 0x90, 0x26, 0xe5, 0x56, 0x15, 0x56, 0x70, 0x02, 0x15, 0x55, 0xaf, 0x54} },
+{ 0x90bd, 16, {0x15, 0x54, 0xef, 0x60, 0x23, 0xe5, 0x56, 0x15, 0x56, 0xae, 0x55, 0x70, 0x02, 0x15, 0x55, 0xf5} },
+{ 0x90cd, 16, {0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x52, 0xe5, 0x52, 0xac, 0x51, 0x70, 0x02, 0x05, 0x51, 0x14} },
+{ 0x90dd, 8, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
+{ 0x90e5, 1, {0x22} },
+{ 0x90e6, 16, {0xe4, 0x90, 0x01, 0xc9, 0xf0, 0x7e, 0x01, 0x7f, 0xca, 0x90, 0x01, 0xbe, 0xee, 0xf0, 0xa3, 0xef} },
+{ 0x90f6, 10, {0xf0, 0x90, 0x01, 0xc2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9100, 16, {0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0xc9, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
+{ 0x9110, 16, {0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
+{ 0x9120, 16, {0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0xc2, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9130, 16, {0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x9140, 16, {0xeb, 0xf0, 0x90, 0x01, 0xc2, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x9150, 16, {0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xc2, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x9160, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x9170, 1, {0x22} },
+{ 0x9171, 16, {0x90, 0x01, 0xc9, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0xbe, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9181, 16, {0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
+{ 0x9191, 16, {0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
+{ 0x91a1, 16, {0x9b, 0x49, 0x90, 0x01, 0xbe, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x91b1, 16, {0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xbe, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x91c1, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x91d1, 1, {0x22} },
+{ 0x91d2, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x50, 0x7b, 0x75, 0x51} },
+{ 0x91e2, 16, {0x80, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x52, 0xf5} },
+{ 0x91f2, 16, {0x53, 0x89, 0x54, 0xfe, 0x12, 0x91, 0x71, 0xef, 0x60, 0x3b, 0xab, 0x52, 0xaa, 0x53, 0xa9, 0x54} },
+{ 0x9202, 16, {0x12, 0x9b, 0x72, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
+{ 0x9212, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
+{ 0x9222, 16, {0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x9232, 5, {0x74, 0x04, 0xf0, 0xd2, 0xaf} },
+{ 0x9237, 1, {0x22} },
+{ 0x9238, 16, {0x12, 0x91, 0xd2, 0xe4, 0xf5, 0x4b, 0x74, 0x36, 0x25, 0x4b, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x4c} },
+{ 0x9248, 16, {0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x4c, 0xff, 0xc4} },
+{ 0x9258, 16, {0x54, 0x0f, 0xf5, 0x4d, 0x60, 0x22, 0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
+{ 0x9268, 16, {0x83, 0xe5, 0x4c, 0xf0, 0xaf, 0x4b, 0x7d, 0x01, 0xe5, 0x4c, 0x45, 0x4d, 0xfb, 0x12, 0x91, 0x00} },
+{ 0x9278, 16, {0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40} },
+{ 0x9288, 16, {0xb5, 0x12, 0x91, 0xd2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9298, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x4b} },
+{ 0x92a8, 16, {0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
+{ 0x92b8, 16, {0x16, 0xaf, 0x4b, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2} },
+{ 0x92c8, 16, {0x80, 0xef, 0xe5, 0x4c, 0xf4, 0x52, 0x3a, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
+{ 0x92d8, 16, {0x90, 0x03, 0x00, 0xe0, 0x60, 0x03, 0x02, 0x93, 0xa5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
+{ 0x92e8, 16, {0x11, 0x8e, 0x4e, 0x8f, 0x4f, 0xc3, 0xe5, 0x4e, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
+{ 0x92f8, 16, {0xbc, 0xe0, 0x65, 0x4f, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8, 0x07} },
+{ 0x9308, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xbc, 0xe0, 0x55, 0x4c, 0x60} },
+{ 0x9318, 16, {0x14, 0xaf, 0x4b, 0x7d, 0x08, 0xe5, 0x4c, 0x55, 0x4f, 0xfb, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05} },
+{ 0x9328, 16, {0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
+{ 0x9338, 16, {0xbc, 0xe5, 0x4f, 0xf0, 0xe4, 0xf5, 0x4b, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x4b, 0xf8, 0xe6, 0xf5} },
+{ 0x9348, 16, {0x4c, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x4c, 0x1e, 0xe5, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x02} },
+{ 0x9358, 16, {0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
+{ 0x9368, 16, {0x4b, 0xf8, 0xe6, 0xf5, 0x4c, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x9378, 16, {0xe0, 0x65, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x04, 0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70} },
+{ 0x9388, 16, {0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x9398, 16, {0x83, 0xe5, 0x4c, 0xf0, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x91, 0xd2} },
+{ 0x93a8, 1, {0x22} },
+{ 0x93a9, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x64, 0x02, 0x93, 0xf0} },
+{ 0x93b5, 16, {0x02, 0x05, 0xa3, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x93c5, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x93d5, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x93e5, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x94, 0x35, 0xe4, 0x7e} },
+{ 0x93f5, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x9405, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x9415, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x9425, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x9435, 16, {0x60, 0x24, 0x02, 0x8a, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
+{ 0x9445, 16, {0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
+{ 0x9455, 8, {0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
+{ 0x945d, 1, {0x00} },
+{ 0x945e, 11, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
+{ 0x9469, 16, {0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
+{ 0x9479, 16, {0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
+{ 0x9489, 16, {0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x1e} },
+{ 0x9499, 10, {0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0xc4, 0xee, 0xf0} },
+{ 0x94a3, 9, {0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x94ac, 2, {0xa9, 0x03} },
+{ 0x94ae, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
+{ 0x94be, 16, {0x57, 0x45, 0x58, 0xf5, 0x59, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
+{ 0x94ce, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
+{ 0x94de, 16, {0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x59, 0xeb} },
+{ 0x94ee, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x59, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
+{ 0x94fe, 16, {0x05, 0x22, 0xe5, 0x57, 0x5c, 0xfe, 0xe5, 0x58, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
+{ 0x950e, 16, {0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
+{ 0x951e, 16, {0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x57, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x58, 0x22, 0x7f} },
+{ 0x952e, 1, {0x00} },
+{ 0x952f, 1, {0x22} },
+{ 0x9530, 16, {0x75, 0x50, 0x02, 0x75, 0x51, 0xb0, 0x90, 0x03, 0x35, 0x74, 0x0f, 0xf0, 0x85, 0x51, 0x82, 0x85} },
+{ 0x9540, 16, {0x50, 0x83, 0xe0, 0xff, 0x90, 0x03, 0x36, 0xf0, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0} },
+{ 0x9550, 16, {0x90, 0x03, 0x37, 0xf0, 0xa3, 0x74, 0xff, 0xf0, 0x75, 0x52, 0x03, 0x75, 0x53, 0x39, 0xef, 0x14} },
+{ 0x9560, 16, {0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x99, 0x98, 0x90, 0x95, 0x6f, 0xf8, 0x28, 0x28, 0x73, 0x02} },
+{ 0x9570, 16, {0x95, 0x90, 0x02, 0x96, 0x2f, 0x02, 0x97, 0x34, 0x02, 0x97, 0x54, 0x02, 0x97, 0x54, 0x02, 0x97} },
+{ 0x9580, 16, {0xef, 0x02, 0x98, 0x2a, 0x02, 0x98, 0x4f, 0x02, 0x99, 0x0d, 0x02, 0x99, 0x39, 0x02, 0x99, 0x65} },
+{ 0x9590, 16, {0xe4, 0xf5, 0x4b, 0xe5, 0x4b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x95a0, 16, {0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xe4, 0xff, 0xe4, 0xfe, 0xef, 0x60, 0x10, 0x74, 0x8a, 0x2e} },
+{ 0x95b0, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5, 0x4c, 0x80, 0x0d, 0x74, 0x8a, 0x2e} },
+{ 0x95c0, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x4c, 0xe5, 0x4f, 0x24, 0x07, 0xf5, 0x82} },
+{ 0x95d0, 16, {0xe4, 0x35, 0x4e, 0xf5, 0x83, 0xe5, 0x4c, 0xf0, 0xe0, 0xf5, 0x4d, 0x65, 0x4c, 0x60, 0x38, 0xe4} },
+{ 0x95e0, 16, {0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfd, 0x05, 0x53, 0xe5, 0x53, 0xaa, 0x52, 0x70, 0x02} },
+{ 0x95f0, 16, {0x05, 0x52, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70} },
+{ 0x9600, 16, {0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe5, 0x4c, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9610, 16, {0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x0e, 0xbe, 0x24, 0x8f, 0x0f, 0xef, 0x64, 0x02, 0x70} },
+{ 0x9620, 16, {0x87, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60, 0x03, 0x02, 0x95, 0x93, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9630, 16, {0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x05, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x03} },
+{ 0x9640, 16, {0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x94, 0xf0, 0xa3, 0x74, 0x5e, 0xf0, 0xe4, 0xf5, 0x4d, 0x7e} },
+{ 0x9650, 16, {0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9660, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xc4, 0xf0, 0x90, 0x01} },
+{ 0x9670, 16, {0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0x74, 0x02} },
+{ 0x9680, 16, {0xf0, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x4c, 0x34, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0} },
+{ 0x9690, 16, {0x70, 0xef, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52} },
+{ 0x96a0, 16, {0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x96b0, 16, {0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x01, 0xc4, 0xf0, 0x75, 0x4d, 0xff, 0x90, 0x01, 0xc4, 0xe0} },
+{ 0x96c0, 16, {0xff, 0x60, 0x37, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfe, 0x05, 0x53, 0xe5, 0x53} },
+{ 0x96d0, 16, {0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x53, 0xe5} },
+{ 0x96e0, 16, {0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53} },
+{ 0x96f0, 16, {0x82, 0x85, 0x52, 0x83, 0xe5, 0x4c, 0xf0, 0x75, 0x4d, 0xff, 0xe5, 0x4d, 0x70, 0x16, 0x74, 0x08} },
+{ 0x9700, 16, {0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35, 0x4e, 0xf5, 0x4e, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60} },
+{ 0x9710, 16, {0x03, 0x02, 0x96, 0x5b, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x05, 0x4b} },
+{ 0x9720, 16, {0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12} },
+{ 0x9730, 16, {0xf0, 0x02, 0x99, 0x9e, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01} },
+{ 0x9740, 16, {0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90, 0x02, 0xf7, 0xf0, 0x90, 0x01, 0xc4} },
+{ 0x9750, 16, {0xf0, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0, 0x74, 0x03, 0xf0, 0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5} },
+{ 0x9760, 16, {0x4d, 0x90, 0x02, 0xf7, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x07, 0x19, 0x90, 0x01, 0xc0} },
+{ 0x9770, 16, {0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x90, 0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9780, 16, {0x83, 0x74, 0xff, 0xf0, 0xf5, 0x4d, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0} },
+{ 0x9790, 16, {0xf0, 0xa3, 0x74, 0x96, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f} },
+{ 0x97a0, 16, {0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5} },
+{ 0x97b0, 16, {0x4d, 0x90, 0x02, 0xf7, 0xe0, 0x55, 0x4d, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f} },
+{ 0x97c0, 16, {0x4c, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x4c, 0x70, 0x04, 0x7f} },
+{ 0x97d0, 16, {0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x4c, 0xe5, 0x4c, 0x70, 0x03, 0x02, 0x99, 0x9e, 0xe4, 0x90} },
+{ 0x97e0, 16, {0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x97f0, 16, {0xff, 0xfd, 0x12, 0x82, 0x50, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0x85} },
+{ 0x9800, 16, {0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x4f, 0x82, 0x85} },
+{ 0x9810, 16, {0x4e, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3} },
+{ 0x9820, 16, {0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x99, 0x9e, 0xc2, 0x04, 0x7e, 0x20, 0x7f, 0x00} },
+{ 0x9830, 16, {0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xe5, 0x4f, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x9840, 16, {0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xe4, 0xff, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9850, 16, {0xf5, 0x4d, 0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0xe5, 0x4b, 0x75, 0xf0, 0x08} },
+{ 0x9860, 16, {0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xf5, 0x83} },
+{ 0x9870, 16, {0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x9880, 16, {0x4b, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x57, 0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d} },
+{ 0x9890, 16, {0xe5, 0x4d, 0x70, 0x11, 0xaf, 0x4b, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20} },
+{ 0x98a0, 16, {0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d, 0x01, 0xfb, 0x75, 0x57} },
+{ 0x98b0, 16, {0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d} },
+{ 0x98c0, 16, {0x02, 0xfb, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xaf, 0x4b, 0x7d} },
+{ 0x98d0, 16, {0x01, 0x12, 0x82, 0x50, 0xe5, 0x4d, 0x60, 0x26, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04} },
+{ 0x98e0, 16, {0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x98f0, 16, {0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x05, 0x4b} },
+{ 0x9900, 16, {0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x50, 0x03, 0x02, 0x98, 0x54, 0x02, 0x99, 0x9e, 0xe4, 0x90, 0x03} },
+{ 0x9910, 16, {0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74} },
+{ 0x9920, 16, {0x1b, 0xf0, 0xa3, 0x74, 0x29, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08} },
+{ 0x9930, 16, {0x60, 0x6c, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x65, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0} },
+{ 0x9940, 16, {0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x52, 0xf0, 0xa3, 0xe5} },
+{ 0x9950, 16, {0x53, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x40, 0xe4, 0x90} },
+{ 0x9960, 16, {0x03, 0x38, 0xf0, 0x80, 0x39, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0} },
+{ 0x9970, 16, {0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x51, 0x24, 0x02, 0x90, 0x03, 0x60, 0xf0, 0xe4, 0x35} },
+{ 0x9980, 16, {0x50, 0x90, 0x03, 0x5f, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x60} },
+{ 0x9990, 16, {0x0d, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x06, 0x90, 0x03, 0x38, 0x74, 0x01, 0xf0, 0x90, 0x01} },
+{ 0x99a0, 16, {0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
+{ 0x99b0, 16, {0xf6, 0x7e, 0x03, 0x7f, 0x35, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d} },
+{ 0x99c0, 11, {0x00, 0x7d, 0x24, 0x12, 0x8e, 0x0c, 0xe4, 0x90, 0x02, 0xaf, 0xf0} },
+{ 0x99cb, 1, {0x22} },
+{ 0x99cc, 16, {0xe4, 0xff, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02} },
+{ 0x99dc, 16, {0x9a, 0x6f, 0x74, 0x36, 0x2f, 0xf8, 0xe6, 0x20, 0xe5, 0x03, 0x02, 0x9a, 0x6f, 0xef, 0x75, 0xf0} },
+{ 0x99ec, 16, {0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xad, 0x82, 0xfc, 0xf5, 0x83, 0xe5, 0x82} },
+{ 0x99fc, 16, {0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x70, 0x63} },
+{ 0x9a0c, 16, {0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01} },
+{ 0x9a1c, 16, {0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x74, 0xf8} },
+{ 0x9a2c, 16, {0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0, 0x70, 0x36, 0xef, 0x25, 0xe0} },
+{ 0x9a3c, 16, {0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xef, 0x25, 0xe0, 0xfe, 0xc3} },
+{ 0x9a4c, 16, {0x74, 0x0c, 0x9e, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xad} },
+{ 0x9a5c, 16, {0x82, 0xfc, 0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xec, 0xf0} },
+{ 0x9a6c, 12, {0xa3, 0xed, 0xf0, 0x0f, 0xef, 0x64, 0x04, 0x60, 0x03, 0x02, 0x99, 0xce} },
+{ 0x9a78, 1, {0x22} },
+{ 0x9a79, 16, {0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
+{ 0x9a89, 16, {0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
+{ 0x9a99, 16, {0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
+{ 0x9aa9, 16, {0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
+{ 0x9ab9, 16, {0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
+{ 0x9ac9, 16, {0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
+{ 0x9ad9, 16, {0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
+{ 0x9ae9, 16, {0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
+{ 0x9af9, 16, {0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
+{ 0x9b09, 16, {0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
+{ 0x9b19, 16, {0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
+{ 0x9b29, 16, {0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
+{ 0x9b39, 16, {0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
+{ 0x9b49, 16, {0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
+{ 0x9b59, 16, {0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
+{ 0x9b69, 9, {0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x9a, 0xc9, 0x73} },
+{ 0x9b72, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x9b82, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9b8b, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x9b9b, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x9bab, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9bb8, 16, {0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
+{ 0x9bc8, 6, {0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
+{ 0x9bce, 16, {0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
+{ 0x9bde, 6, {0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
+{ 0x9be4, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x9bf4, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x9c04, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x9c14, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x9c1c, 16, {0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
+{ 0x9c2c, 16, {0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
+{ 0x9c3c, 16, {0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
+{ 0x9c4c, 16, {0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
+{ 0x9c5c, 16, {0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
+{ 0x9c6c, 16, {0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
+{ 0x9c7c, 16, {0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
+{ 0x9c8c, 16, {0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
+{ 0x9c9c, 16, {0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
+{ 0x9cac, 16, {0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
+{ 0x9cbc, 16, {0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
+{ 0x9ccc, 16, {0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
+{ 0x9cdc, 14, {0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
+{ 0x9cea, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x9cfa, 1, {0x22} },
+{ 0x9cfb, 16, {0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
+{ 0x9d0b, 3, {0xd8, 0xf1, 0x22} },
+{ 0x9d0e, 16, {0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
+{ 0x9d1e, 7, {0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
+{ 0x9d25, 12, {0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9d31, 16, {0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9d, 0x48, 0x12, 0x9d, 0x48, 0x12} },
+{ 0x9d41, 16, {0x9d, 0x48, 0x12, 0x9d, 0x48, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
+{ 0x9d51, 16, {0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
+{ 0x9d61, 1, {0x22} },
{ 0xffff, 0, {0x00} }
};
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 9927b5382..2fa4e30b6 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -56,11 +56,11 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static LIST_HEAD(uhci_list);
-static int rh_submit_urb(urb_t *urb);
-static int rh_unlink_urb(urb_t *urb);
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_generic(urb_t *urb);
-static int uhci_unlink_urb(urb_t *urb);
+static int uhci_unlink_generic(struct urb *urb);
+static int uhci_unlink_urb(struct urb *urb);
#define min(a,b) (((a)<(b))?(a):(b))
@@ -77,9 +77,8 @@ static int uhci_alloc_dev(struct usb_device *dev)
static int uhci_free_dev(struct usb_device *dev)
{
- urb_t *u;
struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
- struct list_head *tmp, *next, *head = &uhci->urb_list;
+ struct list_head *tmp, *head = &uhci->urb_list;
unsigned long flags;
/* Walk through the entire URB list and forcefully remove any */
@@ -87,14 +86,12 @@ static int uhci_free_dev(struct usb_device *dev)
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
- next = tmp->next;
+ tmp = tmp->next;
if (u->dev == dev)
uhci_unlink_urb(u);
-
- tmp = next;
}
nested_unlock(&uhci->urblist_lock, flags);
@@ -115,13 +112,31 @@ static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
unsigned long flags;
nested_lock(&uhci->urblist_lock, flags);
- if (urb->urb_list.next != &urb->urb_list) {
+ if (!list_empty(&urb->urb_list)) {
list_del(&urb->urb_list);
INIT_LIST_HEAD(&urb->urb_list);
}
nested_unlock(&uhci->urblist_lock, flags);
}
+void uhci_set_next_interrupt(struct uhci *uhci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ uhci->skel_term_td.status |= TD_CTRL_IOC;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+void uhci_clear_next_interrupt(struct uhci *uhci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ uhci->skel_term_td.status &= ~TD_CTRL_IOC;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
{
struct uhci_td *td;
@@ -135,8 +150,8 @@ static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
td->frameptr = NULL;
td->nexttd = td->prevtd = NULL;
- td->list.next = td->list.prev = NULL;
td->dev = dev;
+ INIT_LIST_HEAD(&td->list);
usb_inc_dev_use(dev);
@@ -235,23 +250,32 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
*/
static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td, *prevtd;
if (!urbp)
return;
- td = urbp->list.begin;
- if (!td)
+ head = &urbp->list;
+ tmp = head->next;
+ if (head == tmp)
return;
+ td = list_entry(tmp, struct uhci_td, list);
+
/* Add the first TD to the QH element pointer */
qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
prevtd = td;
/* Then link the rest of the TD's */
- for (td = td->list.next; td; td = td->list.next) {
+ tmp = tmp->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
prevtd = td;
@@ -260,9 +284,45 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
prevtd->link = UHCI_PTR_TERM;
}
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* USB_QUEUE_BULK support */
+static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+ struct urb *nurb;
+ struct urb_priv *eurbp, *urbp, *nurbp;
+ struct list_head *tmp;
+ struct uhci_td *td, *ntd;
+ unsigned long flags;
+
+ eurbp = eurb->hcpriv;
+ urbp = urb->hcpriv;
+
+ spin_lock_irqsave(&eurb->lock, flags);
+
+ /* Grab the last URB in the queue */
+ tmp = eurbp->urb_queue_list.prev;
+
+ /* Add this one to the end */
+ list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list);
+
+ spin_unlock_irqrestore(&eurb->lock, flags);
+
+ nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+ nurb = nurbp->urb;
+
+ tmp = nurbp->list.prev;
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = urbp->list.next;
+ ntd = list_entry(tmp, struct uhci_td, list);
+
+ /* No breadth since this will only be called for bulk transfers */
+ td->link = virt_to_bus(ntd);
+}
+
static void uhci_free_td(struct uhci_td *td)
{
- if (td->list.next || td->list.prev)
+ if (!list_empty(&td->list))
dbg("td is still in URB list!");
kmem_cache_free(uhci_td_cachep, td);
@@ -322,6 +382,10 @@ static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhc
static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
{
unsigned long flags;
+ int delayed;
+
+ /* If the QH isn't queued, then we don't need to delay unlink it */
+ delayed = (qh->prevqh || qh->nextqh);
spin_lock_irqsave(&uhci->framelist_lock, flags);
if (qh->prevqh) {
@@ -333,9 +397,20 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
qh->prevqh = qh->nextqh = NULL;
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
- spin_lock_irqsave(&uhci->qh_remove_lock, flags);
- list_add(&qh->remove_list, &uhci->qh_remove_list);
- spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+ if (delayed) {
+ spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+
+ /* Check to see if the remove list is empty */
+ /* Set the IOC bit to force an interrupt so we can remove the QH */
+ if (list_empty(&uhci->qh_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+ /* Add it */
+ list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+ spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+ } else
+ uhci_free_qh(qh);
}
struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
@@ -348,91 +423,86 @@ struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
memset((void *)urbp, 0, sizeof(*urbp));
- urbp->list.begin = urbp->list.end = NULL;
+ urbp->inserttime = jiffies;
+ urbp->urb = urb;
+
+ INIT_LIST_HEAD(&urbp->list);
+ INIT_LIST_HEAD(&urbp->urb_queue_list);
urb->hcpriv = urbp;
- urbp->inserttime = jiffies;
-
usb_inc_dev_use(urb->dev);
return urbp;
}
-static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
td->urb = urb;
- if (!urbp->list.begin)
- urbp->list.begin = td;
-
- if (urbp->list.end) {
- urbp->list.end->list.next = td;
- td->list.prev = urbp->list.end;
- }
- urbp->list.end = td;
+ list_add_tail(&td->list, &urbp->list);
}
-static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td)
{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ urb = NULL; /* No warnings */
- if (!urbp->list.begin && !urbp->list.end)
+ if (list_empty(&td->list))
return;
- if (td->list.prev)
- td->list.prev->list.next = td->list.next;
- else
- urbp->list.begin = td->list.next;
-
- if (td->list.next)
- td->list.next->list.prev = td->list.prev;
- else
- urbp->list.end = td->list.prev;
+ list_del(&td->list);
+ INIT_LIST_HEAD(&td->list);
- td->list.next = td->list.prev = NULL;
td->urb = NULL;
}
-static void uhci_destroy_urb_priv(urb_t *urb)
+static void uhci_destroy_urb_priv(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp;
struct uhci *uhci;
- struct uhci_td *td, *nexttd;
+ struct uhci_td *td;
unsigned long flags;
spin_lock_irqsave(&urb->lock, flags);
urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp)
- return;
+ goto unlock;
if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
- return;
+ goto unlock;
uhci = urb->dev->bus->hcpriv;
- td = urbp->list.begin;
- while (td) {
- nexttd = td->list.next;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
uhci_remove_td_from_urb(urb, td);
uhci_remove_td(uhci, td);
uhci_free_td(td);
-
- td = nexttd;
+ }
+
+ if (!list_empty(&urbp->urb_queue_list)) {
+ list_del(&urbp->urb_queue_list);
+ INIT_LIST_HEAD(&urbp->urb_queue_list);
}
urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
- spin_unlock_irqrestore(&urb->lock, flags);
-
usb_dec_dev_use(urb->dev);
+
+unlock:
+ spin_unlock_irqrestore(&urb->lock, flags);
}
static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
@@ -448,7 +518,7 @@ static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
if (!urbp->fsbr) {
urbp->fsbr = 1;
if (!uhci->fsbr++)
- uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+ uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
}
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -467,7 +537,7 @@ static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
if (urbp->fsbr) {
urbp->fsbr = 0;
if (!--uhci->fsbr)
- uhci->skel_term_td.link = UHCI_PTR_TERM;
+ uhci->skel_term_qh.link = UHCI_PTR_TERM;
}
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -508,7 +578,7 @@ static int uhci_map_status(int status, int dir_out)
/*
* Control transfers
*/
-static int uhci_submit_control(urb_t *urb)
+static int uhci_submit_control(struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -602,10 +672,12 @@ static int uhci_submit_control(urb_t *urb)
if (urb->pipe & TD_CTRL_LS) {
uhci_insert_tds_in_qh(qh, urb, 0);
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+ urbp->queued = 0;
} else {
uhci_insert_tds_in_qh(qh, urb, 1);
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
uhci_inc_fsbr(uhci, urb);
+ urbp->queued = 0;
}
urbp->qh = qh;
@@ -617,10 +689,11 @@ static int uhci_submit_control(urb_t *urb)
return -EINPROGRESS;
}
-static int usb_control_retrigger_status(urb_t *urb);
+static int usb_control_retrigger_status(struct urb *urb);
-static int uhci_result_control(urb_t *urb)
+static int uhci_result_control(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
unsigned int status;
@@ -628,13 +701,16 @@ static int uhci_result_control(urb_t *urb)
if (!urbp)
return -EINVAL;
- td = urbp->list.begin;
- if (!td)
+ head = &urbp->list;
+ tmp = head->next;
+ if (head == tmp)
return -EINVAL;
if (urbp->short_control_packet)
goto status_phase;
+ td = list_entry(tmp, struct uhci_td, list);
+
/* The first TD is the SETUP phase, check the status, but skip */
/* the count */
status = uhci_status_bits(td->status);
@@ -646,10 +722,13 @@ static int uhci_result_control(urb_t *urb)
urb->actual_length = 0;
- td = td->list.next;
-
/* The rest of the TD's (but the last) are data */
- while (td && td->list.next) {
+ tmp = tmp->next;
+ while (tmp != head && tmp->next != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -664,18 +743,18 @@ static int uhci_result_control(urb_t *urb)
if (status)
goto td_error;
-
- td = td->list.next;
}
status_phase:
+ td = list_entry(tmp, struct uhci_td, list);
+
/* Control status phase */
status = uhci_status_bits(td->status);
/* APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of the amount */
/* we requested */
- if (td->status & TD_CTRL_IOC &&
+ if (td->status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
status & TD_CTRL_ACTIVE &&
status & TD_CTRL_NAK)
return 0;
@@ -704,34 +783,37 @@ td_error:
return uhci_map_status(status, uhci_packetout(td->info));
}
-static int usb_control_retrigger_status(urb_t *urb)
+static int usb_control_retrigger_status(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci *uhci = urb->dev->bus->hcpriv;
- struct uhci_td *td, *nexttd;
urbp->short_control_packet = 1;
+ /* Create a new QH to avoid pointer overwriting problems */
+ uhci_remove_qh(uhci, urbp->qh);
+
/* Delete all of the TD's except for the status TD at the end */
- td = urbp->list.begin;
- while (td && td->list.next) {
- nexttd = td->list.next;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head && tmp->next != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
uhci_remove_td_from_urb(urb, td);
uhci_remove_td(uhci, td);
uhci_free_td(td);
-
- td = nexttd;
}
- /* Create a new QH to avoid pointer overwriting problems */
- uhci_remove_qh(uhci, urbp->qh);
-
urbp->qh = uhci_alloc_qh(urb->dev);
- if (!urbp->qh)
+ if (!urbp->qh) {
+ err("unable to allocate new QH for control retrigger");
return -ENOMEM;
+ }
/* One TD, who cares about Breadth first? */
uhci_insert_tds_in_qh(urbp->qh, urb, 0);
@@ -741,6 +823,7 @@ static int usb_control_retrigger_status(urb_t *urb)
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
else
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
+ urbp->queued = 0;
return -EINPROGRESS;
}
@@ -748,7 +831,7 @@ static int usb_control_retrigger_status(urb_t *urb)
/*
* Interrupt transfers
*/
-static int uhci_submit_interrupt(urb_t *urb)
+static int uhci_submit_interrupt(struct urb *urb)
{
struct uhci_td *td;
unsigned long destination, status;
@@ -782,18 +865,25 @@ static int uhci_submit_interrupt(urb_t *urb)
return -EINPROGRESS;
}
-static int uhci_result_interrupt(urb_t *urb)
+static int uhci_result_interrupt(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
unsigned int status;
+ struct uhci_td *td;
if (!urbp)
return -EINVAL;
urb->actual_length = 0;
- for (td = urbp->list.begin; td; td = td->list.next) {
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -836,15 +926,17 @@ td_error:
return uhci_map_status(status, uhci_packetout(td->info));
}
-static void uhci_reset_interrupt(urb_t *urb)
+static void uhci_reset_interrupt(struct urb *urb)
{
+ struct list_head *tmp;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td;
if (!urbp)
return;
- td = urbp->list.begin;
+ tmp = urbp->list.next;
+ td = list_entry(tmp, struct uhci_td, list);
if (!td)
return;
@@ -859,7 +951,7 @@ static void uhci_reset_interrupt(urb_t *urb)
/*
* Bulk transfers
*/
-static int uhci_submit_bulk(urb_t *urb)
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
{
struct uhci_td *td;
struct uhci_qh *qh;
@@ -881,14 +973,14 @@ static int uhci_submit_bulk(urb_t *urb)
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
/* 3 errors */
- status = TD_CTRL_ACTIVE | (3 << 27);
+ status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
if (!(urb->transfer_flags & USB_DISABLE_SPD))
status |= TD_CTRL_SPD;
/*
* Build the DATA TD's
*/
- while (len > 0) {
+ do { /* Allow zero length packets */
int pktsze = len;
if (pktsze > maxsze)
@@ -912,16 +1004,24 @@ static int uhci_submit_bulk(urb_t *urb)
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
- }
+ } while (len > 0);
qh = uhci_alloc_qh(urb->dev);
if (!qh)
return -ENOMEM;
+ urbp->qh = qh;
+
+ /* Always assume depth first */
uhci_insert_tds_in_qh(qh, urb, 1);
- uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
- urbp->qh = qh;
+ if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
+ uhci_append_urb_qh(uhci, eurb, urb);
+ urbp->queued = 1;
+ } else {
+ uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
+ urbp->queued = 0;
+ }
uhci_add_urb_list(uhci, urb);
@@ -936,9 +1036,9 @@ static int uhci_submit_bulk(urb_t *urb)
/*
* Isochronous transfers
*/
-static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end)
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
{
- urb_t *u, *last_urb = NULL;
+ struct urb *last_urb = NULL;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct list_head *tmp, *head = &uhci->urb_list;
int ret = 0;
@@ -947,7 +1047,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
/* look for pending URB's with identical pipe handle */
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
@@ -970,7 +1070,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
return ret;
}
-static int isochronous_find_start(urb_t *urb)
+static int isochronous_find_start(struct urb *urb)
{
int limits;
unsigned int start = 0, end = 0;
@@ -996,7 +1096,7 @@ static int isochronous_find_start(urb_t *urb)
return 0;
}
-static int uhci_submit_isochronous(urb_t *urb)
+static int uhci_submit_isochronous(struct urb *urb)
{
struct uhci_td *td;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1034,10 +1134,10 @@ static int uhci_submit_isochronous(urb_t *urb)
return -EINPROGRESS;
}
-static int uhci_result_isochronous(urb_t *urb)
+static int uhci_result_isochronous(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
int status;
int i, ret = 0;
@@ -1046,9 +1146,15 @@ static int uhci_result_isochronous(urb_t *urb)
urb->actual_length = 0;
- for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) {
+ i = 0;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
int actlength;
+ tmp = tmp->next;
+
if (td->status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -1062,16 +1168,47 @@ static int uhci_result_isochronous(urb_t *urb)
urb->error_count++;
ret = status;
}
+
+ i++;
}
return ret;
}
-static int uhci_submit_urb(urb_t *urb)
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+ struct list_head *tmp, *head = &uhci->urb_list;
+ unsigned long flags;
+ struct urb *u = NULL;
+
+ if (usb_pipeisoc(urb->pipe))
+ return NULL;
+
+ nested_lock(&uhci->urblist_lock, flags);
+ tmp = head->next;
+ while (tmp != head) {
+ u = list_entry(tmp, struct urb, urb_list);
+
+ tmp = tmp->next;
+
+ if (u->dev == urb->dev &&
+ u->pipe == urb->pipe)
+ goto found;
+ }
+ u = NULL;
+
+found:
+ nested_unlock(&uhci->urblist_lock, flags);
+
+ return u;
+}
+
+static int uhci_submit_urb(struct urb *urb)
{
int ret = -EINVAL;
struct uhci *uhci;
unsigned long flags;
+ struct urb *u;
if (!urb)
return -EINVAL;
@@ -1085,6 +1222,10 @@ static int uhci_submit_urb(urb_t *urb)
if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
return rh_submit_urb(urb);
+ u = uhci_find_urb_ep(uhci, urb);
+ if (u && !(urb->transfer_flags & USB_QUEUE_BULK))
+ return -ENXIO;
+
spin_lock_irqsave(&urb->lock, flags);
if (!uhci_alloc_urb_priv(urb)) {
@@ -1100,7 +1241,7 @@ static int uhci_submit_urb(urb_t *urb)
ret = uhci_submit_interrupt(urb);
break;
case PIPE_BULK:
- ret = uhci_submit_bulk(urb);
+ ret = uhci_submit_bulk(urb, u);
break;
case PIPE_ISOCHRONOUS:
ret = uhci_submit_isochronous(urb);
@@ -1124,9 +1265,9 @@ static int uhci_submit_urb(urb_t *urb)
*
* Must be called with urblist_lock acquired
*/
-static void uhci_transfer_result(urb_t *urb)
+static void uhci_transfer_result(struct urb *urb)
{
- urb_t *turb;
+ struct urb *turb;
int proceed = 0, is_ring = 0;
int ret = -EINVAL;
unsigned long flags;
@@ -1206,7 +1347,7 @@ static void uhci_transfer_result(urb_t *urb)
}
}
-static int uhci_unlink_generic(urb_t *urb)
+static int uhci_unlink_generic(struct urb *urb)
{
struct urb_priv *urbp = urb->hcpriv;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1222,12 +1363,21 @@ static int uhci_unlink_generic(urb_t *urb)
/* The interrupt loop will reclaim the QH's */
uhci_remove_qh(uhci, urbp->qh);
+ if (!list_empty(&urbp->urb_queue_list)) {
+ struct list_head *tmp = urbp->urb_queue_list.next;
+ struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+ if (nurbp->queued) {
+ uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+ nurbp->queued = 0;
+ }
+ }
+
uhci_destroy_urb_priv(urb);
return 0;
}
-static int uhci_unlink_urb(urb_t *urb)
+static int uhci_unlink_urb(struct urb *urb)
{
struct uhci *uhci;
int ret = 0;
@@ -1252,7 +1402,13 @@ static int uhci_unlink_urb(urb_t *urb)
urb->status = -ECONNABORTED;
spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+
+ /* Check to see if the remove list is empty */
+ if (list_empty(&uhci->urb_remove_list))
+ uhci_set_next_interrupt(uhci);
+
list_add(&urb->urb_list, &uhci->urb_remove_list);
+
spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
} else {
urb->status = -ENOENT;
@@ -1372,7 +1528,7 @@ static __u8 root_hub_hub_des[] =
/*-------------------------------------------------------------------------*/
/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq(urb_t *urb)
+static int rh_send_irq(struct urb *urb)
{
int i, len = 1;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1399,11 +1555,11 @@ static int rh_send_irq(urb_t *urb)
/*-------------------------------------------------------------------------*/
/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(urb_t *urb);
+static int rh_init_int_timer(struct urb *urb);
static void rh_int_timer_do(unsigned long ptr)
{
- urb_t *urb = (urb_t *)ptr, *u;
+ struct urb *urb = (struct urb *)ptr;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct list_head *tmp, *head = &uhci->urb_list;
struct urb_priv *urbp;
@@ -1422,15 +1578,22 @@ static void rh_int_timer_do(unsigned long ptr)
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, urb_t, urb_list);
+
+ tmp = tmp->next;
urbp = (struct urb_priv *)u->hcpriv;
if (urbp) {
- if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+ /* Check if the FSBR timed out */
+ if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
uhci_dec_fsbr(uhci, u);
- }
- tmp = tmp->next;
+ /* Check if the URB timed out */
+ if (u->timeout && time_after(u->timeout, jiffies)) {
+ u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+ uhci_unlink_urb(u);
+ }
+ }
}
nested_unlock(&uhci->urblist_lock, flags);
@@ -1439,7 +1602,7 @@ static void rh_int_timer_do(unsigned long ptr)
/*-------------------------------------------------------------------------*/
/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(urb_t *urb)
+static int rh_init_int_timer(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1472,7 +1635,7 @@ static int rh_init_int_timer(urb_t *urb)
** Root Hub Control Pipe
*************************/
-static int rh_submit_urb(urb_t *urb)
+static int rh_submit_urb(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
unsigned int pipe = urb->pipe;
@@ -1588,7 +1751,7 @@ static int rh_submit_urb(urb_t *urb)
OK(0);
case RH_PORT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR);
- wait_ms(10);
+ wait_ms(50); /* USB v1.1 7.1.7.3 */
uhci->rh.c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
@@ -1636,6 +1799,11 @@ static int rh_submit_urb(urb_t *urb)
OK(1);
case RH_SET_CONFIGURATION:
OK(0);
+ case RH_GET_INTERFACE | RH_INTERFACE:
+ *(__u8 *)data = 0x00;
+ OK(1);
+ case RH_SET_INTERFACE | RH_INTERFACE:
+ OK(0);
default:
stat = -EPIPE;
}
@@ -1649,7 +1817,7 @@ static int rh_submit_urb(urb_t *urb)
}
/*-------------------------------------------------------------------------*/
-static int rh_unlink_urb(urb_t *urb)
+static int rh_unlink_urb(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1728,6 +1896,8 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
}
spin_unlock(&uhci->urb_remove_lock);
+ uhci_clear_next_interrupt(uhci);
+
/* Walk the list of pending TD's to see which ones completed */
nested_lock(&uhci->urblist_lock, flags);
head = &uhci->urb_list;
@@ -2137,7 +2307,7 @@ int uhci_init(void)
/* We only want to return an error code if ther was an error */
/* and we didn't find a UHCI controller */
- if (retval && uhci_list.next == &uhci_list)
+ if (retval && list_empty(&uhci_list))
goto init_failed;
return 0;
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
index 9f4c45e96..83992bb6a 100644
--- a/drivers/usb/uhci.h
+++ b/drivers/usb/uhci.h
@@ -97,6 +97,10 @@ struct s_nested_lock {
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
+struct uhci_framelist {
+ __u32 frame[UHCI_NUMFRAMES];
+} __attribute__((aligned(4096)));
+
struct uhci_td;
struct uhci_qh {
@@ -106,22 +110,19 @@ struct uhci_qh {
/* Software fields */
/* Can't use list_head since we want a specific order */
- struct uhci_qh *prevqh, *nextqh;
-
struct usb_device *dev; /* The owning device */
+ struct uhci_qh *prevqh, *nextqh;
+
struct list_head remove_list;
} __attribute__((aligned(16)));
-struct uhci_framelist {
- __u32 frame[UHCI_NUMFRAMES];
-} __attribute__((aligned(4096)));
-
/*
* for TD <status>:
*/
#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT 27
#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
@@ -184,10 +185,8 @@ struct uhci_td {
struct usb_device *dev;
struct urb *urb; /* URB this TD belongs to */
- /* We can't use list_head since we need a specific order */
- struct ut_list {
- struct uhci_td *prev, *next;
- } list;
+
+ struct list_head list;
} __attribute__((aligned(16)));
/*
@@ -336,9 +335,12 @@ struct uhci {
};
struct urb_priv {
+ struct urb *urb;
+
struct uhci_qh *qh; /* QH for this URB */
- int fsbr; /* Did this URB turn on FSBR? */
+ int fsbr : 1; /* Did this URB turn on FSBR? */
+ int queued : 1; /* 0 if QH was linked in */
char short_control_packet; /* If we get a short packet during */
/* a control transfer, retrigger */
@@ -346,15 +348,16 @@ struct urb_priv {
unsigned long inserttime; /* In jiffies */
- struct up_list {
- struct uhci_td *begin, *end;
- } list;
+ struct list_head list;
+
+ struct list_head urb_queue_list; /* URB's linked together */
};
/* -------------------------------------------------------------------------
Virtual Root HUB
------------------------------------------------------------------------- */
/* destination of request */
+#define RH_DEVICE 0x00
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index cb6a70621..f42b96f61 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -29,10 +29,10 @@ void usb_major_cleanup(void);
*/
int usb_audio_init(void);
-int usb_cpia_init(void);
int usb_ibmcam_init(void);
int dabusb_init(void);
int plusb_init(void);
+int dsbr100_init(void);
/*
* HCI drivers
@@ -71,9 +71,6 @@ int usb_init(void)
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
-#ifdef CONFIG_USB_CPIA
- usb_cpia_init();
-#endif
#ifdef CONFIG_USB_IBMCAM
usb_ibmcam_init();
#endif
diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c
index bc04d1fca..e8da9e376 100644
--- a/drivers/usb/usb-debug.c
+++ b/drivers/usb/usb-debug.c
@@ -4,11 +4,16 @@
* I just want these out of the way where they aren't in your
* face, but so that you can still use them..
*/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index b134107da..7c4a72c6d 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -49,7 +49,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#define OHCI_USE_NPS
+#define OHCI_USE_NPS // force NoPowerSwitching mode
#include "usb-ohci.h"
@@ -61,6 +61,12 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
#include <linux/pmu.h>
#endif
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) \
+ | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
@@ -143,16 +149,18 @@ static void urb_print (urb_t * urb, char * str, int small)
printk ("%s stat:%d\n", i < len? "...": "", urb->status);
}
}
-
}
-/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
void ep_print_int_eds (ohci_t * ohci, char * str) {
int i, j;
__u32 * ed_p;
for (i= 0; i < 32; i++) {
j = 5;
- printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
ed_p = &(ohci->hcca.int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
while (*ed_p != 0 && j--) {
ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
printk (" ed: %4x;", ed->hwINFO);
@@ -161,7 +169,161 @@ void ep_print_int_eds (ohci_t * ohci, char * str) {
printk ("\n");
}
}
-
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ if (value)
+ dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+ // intrdisable always same as intrenable
+ // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp, ndp, i;
+
+ temp = readl (&regs->roothub.a);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = readl (&regs->roothub.b);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = readl (&regs->roothub.status);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = readl (&regs->roothub.portstatus [i]);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller %p state", controller->regs);
+
+ // dumps some of the state we know about
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca.frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
#endif
@@ -365,12 +527,12 @@ static int sohci_unlink_urb (urb_t * urb)
if (!urb) /* just to be sure */
return -EINVAL;
+ ohci = (ohci_t *) urb->dev->bus->hcpriv;
+
#ifdef DEBUG
urb_print (urb, "UNLINK", 1);
#endif
- ohci = (ohci_t *) urb->dev->bus->hcpriv;
-
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
@@ -448,8 +610,8 @@ static int sohci_free_dev (struct usb_device * usb_dev)
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
- if (cnt > 0) {
- dev->wait = &wait;
+ if (cnt > 0) {
+ dev->wait = &wait;
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout (HZ / 10);
remove_wait_queue (&op_wakeup, &wait);
@@ -673,10 +835,12 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
}
}
}
- for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
+ for (i = int_branch; i < 32; i += interval)
+ ohci->ohci_int_load[i] -= ed->int_load;
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_INT");
-#endif break;
+#endif
+ break;
case ISO:
if (ohci->ed_isotail == ed)
@@ -787,10 +951,10 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
switch (ed->type) {
case CTRL: /* stop CTRL list */
- writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control);
break;
case BULK: /* stop BULK list */
- writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control);
break;
}
}
@@ -1012,8 +1176,10 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
if (bulk) writel (0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */
- if (!ohci->ed_rm_list[!frame]) /* start CTRL u. BULK list */
- writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);
+ if (!ohci->ed_rm_list[!frame]) { /* enable CTRL and BULK lists */
+ ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
ohci->ed_rm_list[frame] = NULL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
@@ -1112,6 +1278,7 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
* Virtual Root Hub
*-------------------------------------------------------------------------*/
+/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
@@ -1170,23 +1337,8 @@ static __u8 root_hub_config_des[] =
0xff /* __u8 ep_bInterval; 255 ms */
};
-/*
-For OHCI we need just the 2nd Byte, so we
-don't need this constant byte-array
+/* Hub class-specific descriptor is constructed dynamically */
-static __u8 root_hub_hub_des[] =
-{
- 0x00, * __u8 bLength; *
- 0x29, * __u8 bDescriptorType; Hub-descriptor *
- 0x02, * __u8 bNbrPorts; *
- 0x00, * __u16 wHubCharacteristics; *
- 0x00,
- 0x01, * __u8 bPwrOn2pwrGood; 2ms *
- 0x00, * __u8 bHubContrCurrent; 0 mA *
- 0x00, * __u8 DeviceRemovable; *** 8 Ports max *** *
- 0xff * __u8 PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
/*-------------------------------------------------------------------------*/
@@ -1201,13 +1353,16 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
__u8 data[8];
- num_ports = readl (&ohci->regs->roothub.a) & 0xff;
- *(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
+ num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP;
+ *(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+ ? 1: 0;
ret = *(__u8 *) data;
for ( i = 0; i < num_ports; i++) {
*(__u8 *) (data + (i + 1) / 8) |=
- ((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
+ ((readl (&ohci->regs->roothub.portstatus[i]) &
+ (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+ ? 1: 0) << ((i + 1) % 8);
ret += *(__u8 *) (data + (i + 1) / 8);
}
len = i/8 + 1;
@@ -1221,7 +1376,7 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
static void rh_int_timer_do (unsigned long ptr)
{
@@ -1267,10 +1422,10 @@ static int rh_init_int_timer (urb_t * urb)
/*-------------------------------------------------------------------------*/
-#define OK(x) len = (x); break
+#define OK(x) len = (x); break
#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT readl(&ohci->regs->roothub.status)
+#define RD_RH_STAT readl(&ohci->regs->roothub.status)
#define RD_RH_PORTSTAT readl(&ohci->regs->roothub.portstatus[wIndex-1])
/* request to virtual root hub */
@@ -1309,6 +1464,10 @@ static int rh_submit_urb (urb_t * urb)
wValue = le16_to_cpu (cmd->value);
wIndex = le16_to_cpu (cmd->index);
wLength = le16_to_cpu (cmd->length);
+
+ dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+ bmRType_bReq, wLength);
+
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
@@ -1325,7 +1484,9 @@ static int rh_submit_urb (urb_t * urb)
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (RD_RH_STAT & 0x7fff7fff); OK (4);
+ *(__u32 *) data_buf = cpu_to_le32 (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
@@ -1370,11 +1531,15 @@ static int rh_submit_urb (urb_t * urb)
case (RH_PORT_SUSPEND):
WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
case (RH_PORT_POWER):
WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
}
break;
@@ -1438,11 +1603,13 @@ static int rh_submit_urb (urb_t * urb)
case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
default:
+ dbg ("unsupported root hub command");
status = TD_CC_STALL;
}
- dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
- dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
+#ifdef DEBUG
+ ohci_dump_roothub (ohci, 0);
+#endif
len = min(len, leni);
if (data != data_buf)
@@ -1473,39 +1640,44 @@ static int rh_unlink_urb (urb_t * urb)
* HC functions
*-------------------------------------------------------------------------*/
-/* reset the HC not the BUS */
+/* reset the HC and BUS */
-static void hc_reset (ohci_t * ohci)
+static int hc_reset (ohci_t * ohci)
{
int timeout = 30;
int smm_timeout = 50; /* 0,5 sec */
- if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
- writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
dbg("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & 0x100) {
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
if (--smm_timeout == 0) {
err("USB HC TakeOver failed!");
- break;
+ return -1;
}
}
}
- writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
- /* this seems to be needed for the lucent controller on powerbooks.. */
- writel (0, &ohci->regs->control); /* Move USB to reset state */
+
+ /* Reset USB (needed by some controllers) */
+ writel (0, &ohci->regs->control);
- writel (1, &ohci->regs->cmdstatus); /* HC Reset */
- while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+ /* HC Reset requires max 10 ms delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--timeout == 0) {
err("USB HC reset timed out!");
- return;
+ return -1;
}
udelay (1);
}
ohci->disabled = 0;
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -1516,7 +1688,7 @@ static void hc_reset (ohci_t * ohci)
static int hc_start (ohci_t * ohci)
{
- unsigned int mask;
+ __u32 mask;
unsigned int fminterval;
struct usb_device * usb_dev;
struct ohci_device * dev;
@@ -1535,31 +1707,35 @@ static int hc_start (ohci_t * ohci)
writel (fminterval, &ohci->regs->fminterval);
writel (0x628, &ohci->regs->lsthresh);
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
+
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-
- writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
writel (mask, &ohci->regs->intrstatus);
-#ifdef OHCI_USE_NPS
- writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+#ifdef OHCI_USE_NPS
+ writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
- writel (0x10000, &ohci->regs->roothub.status);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+ // POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
+#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
-
+ ohci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev) return -1;
+ if (!usb_dev)
+ return -ENOMEM;
dev = usb_to_ohci (usb_dev);
ohci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
- return -1;
+ return -ENODEV;
}
return 0;
@@ -1582,11 +1758,12 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
return;
}
- dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
-
+ // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+
if (ints & OHCI_INTR_UE) {
ohci->disabled++;
err ("OHCI Unrecoverable Error, controller disabled");
+ // e.g. due to PCI Master/Target Abort
}
if (ints & OHCI_INTR_WDH) {
@@ -1661,8 +1838,9 @@ static void hc_release_ohci (ohci_t * ohci)
dbg("USB HC release ohci");
/* disconnect all devices */
- if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
-
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+
hc_reset (ohci);
writel (OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
@@ -1698,6 +1876,7 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
#endif
printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
(unsigned long) mem_base, bufp);
+ printk(KERN_INFO __FILE__ ": %s\n", dev->name);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
@@ -1707,12 +1886,16 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
- hc_reset (ohci);
+ if (hc_reset (ohci) < 0) {
+ hc_release_ohci (ohci);
+ return -ENODEV;
+ }
+
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
usb_register_bus (ohci->bus);
- if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+ if (request_irq (irq, hc_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
struct pm_dev *pmdev;
ohci->irq = irq;
@@ -1724,6 +1907,10 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
if (pmdev)
pmdev->data = ohci;
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+
return 0;
}
err("request interrupt %d failed", irq);
@@ -1787,7 +1974,8 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
case PBOOK_WAKE:
writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
enable_irq (ohci->irq);
break;
}
@@ -1801,22 +1989,24 @@ static struct pmu_sleep_notifier ohci_sleep_notifier = {
#endif /* CONFIG_PMAC_PBOOK */
/*-------------------------------------------------------------------------*/
-
+
static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
{
ohci_t * ohci = (ohci_t*) dev->data;
+ int temp = 0;
+
if (ohci) {
switch (rqst) {
case PM_SUSPEND:
- dbg("USB-Bus suspend: %p", ohci);
- writel (ohci->hc_control = 0xFF, &ohci->regs->control);
- wait_ms (10);
+ dbg("USB-Bus suspend: %p", ohci->regs);
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+ hc_reset (ohci);
break;
case PM_RESUME:
- dbg("USB-Bus resume: %p", ohci);
- writel (ohci->hc_control = 0x7F, &ohci->regs->control);
- wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ dbg("USB-Bus resume: %p", ohci->regs);
+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
+ err ("can't restart controller, %d", temp);
break;
}
}
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index d1b77c8f5..7a3afe5c4 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -27,7 +27,6 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
@@ -39,14 +38,6 @@
#include "usb-storage.h"
#include "usb-storage-debug.h"
-/*
- * This is the size of the structure Scsi_Host_Template. We create
- * an instance of this structure in this file and this is a check
- * to see if this structure may have changed within the SCSI module.
- * This is by no means foolproof, but it does help us some.
- */
-#define SCSI_HOST_TEMPLATE_SIZE (104)
-
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
*/
@@ -76,7 +67,11 @@ typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
/* we allocate one of these for every device that we remember */
struct us_data {
struct us_data *next; /* next device */
+
+ /* the device we're working with */
+ struct semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
+
unsigned int flags; /* from filter initially */
/* information about the device -- only good if device is attached */
@@ -113,7 +108,7 @@ struct us_data {
unsigned int irqpipe; /* pipe for release_irq */
/* mutual exclusion structures */
- struct semaphore notify; /* wait for thread to begin */
+ struct semaphore notify; /* thread begin/end */
struct semaphore sleeper; /* to sleep on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -131,7 +126,7 @@ struct us_data {
/* The list of structures and the protective lock for them */
static struct us_data *us_list;
-spinlock_t us_list_spinlock = SPIN_LOCK_UNLOCKED;
+struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
static void storage_disconnect(struct usb_device *dev, void *ptr);
@@ -249,43 +244,415 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
{
int i;
unsigned int total = 0;
+ struct scatterlist *sg;
- /* always zero for some commands */
- switch (srb->cmnd[0]) {
- case SEEK_6:
- case SEEK_10:
- case REZERO_UNIT:
- case ALLOW_MEDIUM_REMOVAL:
- case START_STOP:
- case TEST_UNIT_READY:
- return 0;
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the scatter-gather segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
- /* FIXME: these should be removed and tested */
- case REQUEST_SENSE:
- case INQUIRY:
- case MODE_SENSE:
- return srb->cmnd[4];
+ return total;
+ }
+ else
+ /* Just return the length of the buffer */
+ return srb->request_bufflen;
+}
- /* FIXME: these should be removed and tested */
- case LOG_SENSE:
- case MODE_SENSE_10:
- return (srb->cmnd[7] << 8) + srb->cmnd[8];
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
- default:
- break;
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int need_auto_sense;
+ int result;
+
+ /* send the command to the transport layer */
+ result = us->transport(srb, us);
+
+ /* Determine if we need to auto-sense
+ *
+ * I normally don't use a flag like this, but it's almost impossible
+ * to understand what's going on here if I don't.
+ */
+ need_auto_sense = 0;
+
+ /*
+ * If we're running the CB transport, which is incapable
+ * of determining status on it's own, we need to auto-sense almost
+ * every time.
+ */
+ if (us->protocol == US_PR_CB) {
+ US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ need_auto_sense = 1;
+
+ /* There are some exceptions to this. Notably, if this is
+ * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+ * then it is impossible to truly determine status.
+ */
+ if (us->subclass == US_SC_UFI &&
+ ((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY)))
+ need_auto_sense = 0;
}
- if (srb->use_sg) {
- struct scatterlist *sg;
+ /*
+ * If we have an error, we're going to do a REQUEST_SENSE
+ * automatically. Note that we differentiate between a command
+ * "failure" and an "error" in the transport mechanism.
+ */
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ US_DEBUGP("-- transport indicates command failure\n");
+ need_auto_sense = 1;
+ }
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- transport indicates transport failure\n");
+ need_auto_sense = 0;
+ srb->result = DID_ERROR << 16;
+ return;
+ }
- sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++) {
- total += sg[i].length;
+ /*
+ * Also, if we have a short transfer on a command that can't have
+ * a short transfer, we're going to do this.
+ */
+ if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+ !((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY) ||
+ (srb->cmnd[0] == MODE_SENSE) ||
+ (srb->cmnd[0] == LOG_SENSE) ||
+ (srb->cmnd[0] == MODE_SENSE_10))) {
+ US_DEBUGP("-- unexpectedly short transfer\n");
+ need_auto_sense = 1;
+ }
+
+ /* Now, if we need to do the auto-sense, let's do it */
+ if (need_auto_sense) {
+ int temp_result;
+ void* old_request_buffer;
+ int old_sg;
+
+ US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+
+ srb->cmnd[0] = REQUEST_SENSE;
+ srb->cmnd[1] = 0;
+ srb->cmnd[2] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[4] = 18;
+ srb->cmnd[5] = 0;
+
+ /* set the buffer length for transfer */
+ old_request_buffer = srb->request_buffer;
+ old_sg = srb->use_sg;
+ srb->request_bufflen = 18;
+ srb->request_buffer = us->srb->sense_buffer;
+
+ /* FIXME: what if this command fails? */
+ temp_result = us->transport(us->srb, us);
+ US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+ US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ srb->sense_buffer[2] & 0xf,
+ srb->sense_buffer[12],
+ srb->sense_buffer[13]);
+
+ /* set the result so the higher layers expect this data */
+ srb->result = CHECK_CONDITION;
+
+ /* we're done here */
+ srb->request_buffer = old_request_buffer;
+ srb->use_sg = old_sg;
+ }
+
+ /* Set return code, if necessary */
+ if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
+ srb->result = GOOD;
+ if (!need_auto_sense)
+ srb->result = GOOD;
+}
+
+/*
+ * Control/Bulk/Interrupt transport
+ */
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
+{
+ struct us_data *us = (struct us_data *)dev_id;
+
+ US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+ US_DEBUGP("-- IRQ data length is %d\n", len);
+ US_DEBUGP("-- IRQ state is %d\n", state);
+
+ /* is the device removed? */
+ if (state != -ENOENT) {
+ /* save the data for interpretation later */
+ us->ip_data = le16_to_cpup((__u16 *)buffer);
+ US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
+
+ /* was this a wanted interrupt? */
+ if (us->ip_wanted) {
+ us->ip_wanted = 0;
+ up(&(us->ip_waitq));
+ } else
+ US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ } else
+ US_DEBUGP("-- device has been removed\n");
+
+ /* This return code is truly meaningless -- and I mean truly. It gets
+ * ignored by other layers. It used to indicate if we wanted to get
+ * another interrupt or disable the interrupt callback
+ */
+ return 0;
+}
+
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
+
+ /* check the return code for the command */
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+ if (result < 0) {
+ /* STALL must be cleared when they are detected */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
}
- return total;
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
}
- else
- return srb->request_bufflen;
+
+ /* Set up for status notification */
+ us->ip_wanted = 1;
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb)) {
+ us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+ }
+
+ /* STATUS STAGE */
+
+ /* go to sleep until we get this interrupt */
+ down(&(us->ip_waitq));
+
+ /* if we were woken up by a reset instead of the actual interrupt */
+ if (us->ip_wanted) {
+ US_DEBUGP("Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+
+ /* UFI gives us ASC and ASCQ, like a request sense
+ *
+ * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+ * devices, so we ignore the information for those commands. Note
+ * that this means we could be ignoring a real error on these
+ * commands, but that can't be helped.
+ */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmnd[0] == REQUEST_SENSE ||
+ srb->cmnd[0] == INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* If not UFI, we interpret the data as a result code
+ * The first byte should always be a 0x0
+ * The second byte & 0x0F should be 0x0 for good, otherwise error
+ */
+ switch ((us->ip_data & 0xFF0F)) {
+ case 0x0000:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0001:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("CBI_transport() reached end of function\n");
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Control/Bulk transport
+ */
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
+
+ /* check the return code for the command */
+ if (result < 0) {
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+
+ /* a stall is a fatal condition from the device */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb)) {
+ us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+ }
+
+
+ /* STATUS STAGE */
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Bulk only transport
+ */
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ struct bulk_cb_wrap bcb;
+ struct bulk_cs_wrap bcs;
+ int result;
+ int pipe;
+ int partial;
+
+ /* set up the command wrapper */
+ bcb.Signature = US_BULK_CB_SIGN;
+ bcb.DataTransferLength = us_transfer_length(srb);
+ bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+ bcb.Tag = srb->serial_number;
+ bcb.Lun = srb->cmnd[1] >> 5;
+ bcb.Length = srb->cmd_len;
+
+ /* construct the pipe handle */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* copy the command payload */
+ memset(bcb.CDB, 0, sizeof(bcb.CDB));
+ memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+
+ /* send it to out endpoint */
+ US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+ bcb.Signature, bcb.Tag, bcb.Lun, bcb.DataTransferLength,
+ bcb.Flags, bcb.Length);
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
+ US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+ US_DEBUGP("Bulk command transfer result=%d\n", result);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ /* if the command transfered well, then we go to the data stage */
+ if (result == 0) {
+ /* send/receive data payload, if there is any */
+ if (bcb.DataTransferLength) {
+ us_transfer(srb, bcb.Flags);
+ US_DEBUGP("Bulk data transfer result 0x%x\n",
+ srb->result);
+ }
+ }
+
+ /* See flow chart on pg 15 of the Bulk Only Transport spec for
+ * an explanation of how this code works.
+ */
+
+ /* construct the pipe handle */
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+
+ /* get CSW for device status */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* did the attempt to read the CSW fail? */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+
+ /* get the status again */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* if it fails again, we need a reset and return an error*/
+ if (result == -EPIPE) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ /* if we still have a failure at this point, we're in trouble */
+ if (result) {
+ US_DEBUGP("Bulk status result = %d\n", result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* check bulk status */
+ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
+ if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+ bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+ US_DEBUGP("Bulk logical error\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* based on the status code, we report good or bad */
+ switch (bcs.Status) {
+ case US_BULK_STAT_OK:
+ /* command good -- note that we could be short on data */
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ /* phase error */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
}
/***********************************************************************
@@ -295,7 +662,6 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
- int result;
/* Fix some commands -- this is a form of mode translation
* ATAPI devices only accept 12 byte long commands
@@ -308,7 +674,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmd_len = 12;
/* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
+ switch (srb->cmnd[0]) {
/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
case MODE_SENSE:
@@ -350,60 +716,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
} /* end switch on cmnd[0] */
/* send the command to the transport layer */
- result = us->transport(srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
-
- /*
- * If we have an error, we're going to do a
- * REQUEST_SENSE automatically
- */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- void* old_request_buffer;
- int old_sg;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
- }
+ invoke_transport(srb, us);
/* Fix the MODE_SENSE data if we translated the command
*/
@@ -424,7 +737,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
*/
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
}
}
@@ -433,7 +746,6 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
- int result;
/* fix some commands -- this is a form of mode translation
* UFI devices only accept 12 byte long commands
@@ -446,11 +758,11 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmd_len = 12;
/* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
+ switch (srb->cmnd[0]) {
/* for INQUIRY, UFI devices only ever return 36 bytes */
case INQUIRY:
- us->srb->cmnd[4] = 36;
+ srb->cmnd[4] = 36;
break;
/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
@@ -482,13 +794,13 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
/* again, for MODE_SENSE_10, we get the minimum (8) */
case MODE_SENSE_10:
- us->srb->cmnd[7] = 0;
- us->srb->cmnd[8] = 8;
+ srb->cmnd[7] = 0;
+ srb->cmnd[8] = 8;
break;
/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
case REQUEST_SENSE:
- us->srb->cmnd[4] = 18;
+ srb->cmnd[4] = 18;
break;
/* change READ_6/WRITE_6 to READ_10/WRITE_10, which
@@ -509,63 +821,10 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmnd[0] = srb->cmnd[0] | 0x20;
break;
} /* end switch on cmnd[0] */
-
- /* send the command to the transport layer */
- result = us->transport(srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
-
- /*
- * If we have an error, we're going to do a
- * REQUEST_SENSE automatically
- */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- void* old_request_buffer;
- int old_sg;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
- }
-
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
+
/* Fix the MODE_SENSE data here if we had to translate the command
*/
if (old_cmnd == MODE_SENSE) {
@@ -585,15 +844,13 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
*/
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
}
}
static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
{
- unsigned int result = 0;
-
/* This code supports devices which do not support {READ|WRITE}_6
* Apparently, neither Windows or MacOS will use these commands,
* so some devices do not support them
@@ -601,155 +858,76 @@ static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
if (us->flags & US_FL_MODE_XLATE) {
/* translate READ_6 to READ_10 */
- if (us->srb->cmnd[0] == 0x08) {
+ if (srb->cmnd[0] == 0x08) {
/* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
+ srb->cmnd[9] = us->srb->cmnd[5];
/* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[6];
- us->srb->cmnd[7] = 0;
+ srb->cmnd[8] = us->srb->cmnd[6];
+ srb->cmnd[7] = 0;
/* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
+ srb->cmnd[6] = 0;
/* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
/* LUN and other info in cmnd[1] can stay */
/* fix command code */
- us->srb->cmnd[0] = 0x28;
+ srb->cmnd[0] = 0x28;
US_DEBUGP("Changing READ_6 to READ_10\n");
- US_DEBUG(us_show_command(us->srb));
+ US_DEBUG(us_show_command(srb));
}
/* translate WRITE_6 to WRITE_10 */
- if (us->srb->cmnd[0] == 0x0A) {
+ if (srb->cmnd[0] == 0x0A) {
/* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
+ srb->cmnd[9] = us->srb->cmnd[5];
/* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[4];
- us->srb->cmnd[7] = 0;
+ srb->cmnd[8] = us->srb->cmnd[4];
+ srb->cmnd[7] = 0;
/* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
+ srb->cmnd[6] = 0;
/* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
/* LUN and other info in cmnd[1] can stay */
/* fix command code */
- us->srb->cmnd[0] = 0x2A;
+ srb->cmnd[0] = 0x2A;
US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
US_DEBUG(us_show_command(us->srb));
}
} /* if (us->flags & US_FL_MODE_XLATE) */
-
- /* send the command to the transport layer */
- result = us->transport(us->srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
- /* if we have an error, we're going to do a REQUEST_SENSE
- * automatically */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- int old_sg;
- void* old_request_buffer;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
- /* set up the REQUEST_SENSE command and parameters */
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->use_sg = old_sg;
- us->srb->request_buffer = old_request_buffer;
- return;
- }
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
/* fix the results of an INQUIRY */
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
((unsigned char*)us->srb->request_buffer)[2] |= 2;
}
}
/***********************************************************************
- * Transport routines
+ * Reset routines
***********************************************************************/
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
-{
- struct us_data *us = (struct us_data *)dev_id;
-
- US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-
- /* save the data for interpretation later */
- if (state != USB_ST_REMOVED) {
- us->ip_data = le16_to_cpup((__u16 *)buffer);
- US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
- }
-
- /* was this a wanted interrupt? */
- if (us->ip_wanted) {
- us->ip_wanted = 0;
- up(&(us->ip_waitq));
- } else {
- US_DEBUGP("ERROR: Unwanted interrupt received!\n");
- }
-
- /* This return code is truly meaningless -- and I mean truly. It gets
- * ignored by other layers. It used to indicate if we wanted to get
- * another interrupt or disable the interrupt callback
- */
- return 0;
-}
-
/* This issues a CB[I] Reset to the device in question
*/
static int CB_reset(struct us_data *us)
@@ -757,7 +935,7 @@ static int CB_reset(struct us_data *us)
unsigned char cmd[12];
int result;
- US_DEBUGP("CB_reset\n");
+ US_DEBUGP("CB_reset() called\n");
memset(cmd, 0xFF, sizeof(cmd));
cmd[0] = SEND_DIAGNOSTIC;
@@ -780,162 +958,6 @@ static int CB_reset(struct us_data *us)
return 0;
}
-/*
- * Control/Bulk/Interrupt transport
- */
-static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
-
- US_DEBUGP("CBI gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
-
- /* check the return code for the command */
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
- if (result < 0) {
- /* a stall is a fatal condition from the device */
- if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe. Clearing\n");
- US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
- usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0)));
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* FIXME: we need to handle NAKs here */
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* Set up for status notification */
- us->ip_wanted = 1;
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- US_DEBUGP("CBI data stage result is 0x%x\n", result);
- }
-
- /* STATUS STAGE */
-
- /* go to sleep until we get this interrupt */
- down(&(us->ip_waitq));
-
- /* if we were woken up by a reset instead of the actual interrupt */
- if (us->ip_wanted) {
- US_DEBUGP("Did not get interrupt on CBI\n");
- us->ip_wanted = 0;
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
-
- /* UFI gives us ASC and ASCQ, like a request sense
- *
- * REQUEST_SENSE and INQUIRY don't affect the sense data, so we
- * ignore the information for those commands
- */
- if (us->subclass == US_SC_UFI) {
- if (srb->cmnd[0] == REQUEST_SENSE ||
- srb->cmnd[0] == INQUIRY)
- return USB_STOR_TRANSPORT_GOOD;
- else
- if (us->ip_data)
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
- }
-
- /* otherwise, we interpret the data normally */
- switch (us->ip_data) {
- case 0x0001:
- return USB_STOR_TRANSPORT_GOOD;
- case 0x0002:
- return USB_STOR_TRANSPORT_FAILED;
- default:
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- US_DEBUGP("CBI_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
-}
-
-/*
- * Control/Bulk transport
- */
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
- __u8 status[2];
-
- US_DEBUGP("CBC gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
-
- /* check the return code for the command */
- if (result < 0) {
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
-
- /* a stall is a fatal condition from the device */
- if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe. Clearing\n");
- US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
- usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0)));
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* FIXME: we need to handle NAKs here */
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- US_DEBUGP("CBC data stage result is 0x%x\n", result);
- }
-
-
- /* STATUS STAGE */
- /* FIXME: this is wrong */
- result = usb_control_msg(us->pusb_dev,
- usb_rcvctrlpipe(us->pusb_dev,0),
- USB_REQ_GET_STATUS, USB_DIR_IN |
- USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- 0, us->ifnum, status, sizeof(status), HZ*5);
-
- if (result < 0) {
- US_DEBUGP("CBC Status stage returns %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- US_DEBUGP("Got CB status 0x%x 0x%x\n", status[0], status[1]);
- if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
- ( (status[0] & ~3) || status[1]))
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
-
- US_DEBUGP("CB_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
-}
-
/* FIXME: Does this work? */
static int Bulk_reset(struct us_data *us)
{
@@ -961,135 +983,31 @@ static int Bulk_reset(struct us_data *us)
return result;
}
-/*
- * Bulk only transport
- */
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- struct bulk_cb_wrap bcb;
- struct bulk_cs_wrap bcs;
- int result;
- int pipe;
- int partial;
-
- /* set up the command wrapper */
- bcb.Signature = US_BULK_CB_SIGN;
- bcb.DataTransferLength = us_transfer_length(srb);
- bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
- bcb.Tag = srb->serial_number;
- bcb.Lun = 0;
- bcb.Length = srb->cmd_len;
-
- /* construct the pipe handle */
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
- /* copy the command payload */
- memset(bcb.CDB, 0, sizeof(bcb.CDB));
- memcpy(bcb.CDB, srb->cmnd, bcb.Length);
-
- /* send it to out endpoint */
- US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
- bcb.Signature, bcb.Tag, bcb.DataTransferLength,
- bcb.Flags, bcb.Length);
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
- US_BULK_CB_WRAP_LEN, &partial, HZ*5);
- US_DEBUGP("Bulk command transfer result=%d\n", result);
-
- /* if we stall, we need to clear it before we go on */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
- }
-
- /* if the command transfered well, then we go to the data stage */
- if (result == 0) {
- /* send/receive data payload, if there is any */
- if (bcb.DataTransferLength) {
- us_transfer(srb, bcb.Flags);
- US_DEBUGP("Bulk data transfer result 0x%x\n",
- srb->result);
- }
- }
-
- /* See flow chart on pg 15 of the Bulk Only Transport spec for
- * an explanation of how this code works.
- */
-
- /* construct the pipe handle */
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-
- /* get CSW for device status */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* did the attempt to read the CSW fail? */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
-
- /* get the status again */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* if it fails again, we need a reset and return an error*/
- if (result == -EPIPE) {
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
- }
-
- /* if we still have a failure at this point, we're in trouble */
- if (result) {
- US_DEBUGP("Bulk status result = %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* check bulk status */
- US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
- bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
- if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
- bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
- US_DEBUGP("Bulk logical error\n");
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* based on the status code, we report good or bad */
- switch (bcs.Status) {
- case US_BULK_STAT_OK:
- /* command good -- note that we could be short on data */
- return USB_STOR_TRANSPORT_GOOD;
-
- case US_BULK_STAT_FAIL:
- /* command failed */
- return USB_STOR_TRANSPORT_FAILED;
-
- case US_BULK_STAT_PHASE:
- /* phase error */
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* we should never get here, but if we do, we're in trouble */
- return USB_STOR_TRANSPORT_ERROR;
-}
-
/***********************************************************************
* Host functions
***********************************************************************/
-/* detect adapter (always true ) */
+static const char* us_info(struct Scsi_Host *host)
+{
+ return "SCSI emulation for USB Mass Storage devices\n";
+}
+
+/* detect a virtual adapter (always works) */
static int us_detect(struct SHT *sht)
{
- /* FIXME - not nice at all, but how else ? */
- struct us_data *us = (struct us_data *)sht->proc_dir;
- char name[32];
+ struct us_data *us;
+ char local_name[32];
+
+ /* This is not nice at all, but how else are we to get the
+ * data here? */
+ us = (struct us_data *)sht->proc_dir;
- /* set up our name */
- sprintf(name, "usbscsi%d", us->host_number);
- sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+ /* set up the name of our subdirectory under /proc/scsi/ */
+ sprintf(local_name, "usb-storage-%d", us->host_number);
+ sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
if (!sht->proc_name)
return 0;
- strcpy(sht->proc_name, name);
+ strcpy(sht->proc_name, local_name);
/* we start with no /proc directory entry */
sht->proc_dir = NULL;
@@ -1105,36 +1023,34 @@ static int us_detect(struct SHT *sht)
/* odd... didn't register properly. Abort and free pointers */
kfree(sht->proc_name);
sht->proc_name = NULL;
- sht->name = NULL;
return 0;
}
-/* release - must be here to stop scsi
- * from trying to release IRQ etc.
- * Kill off our data
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
*/
static int us_release(struct Scsi_Host *psh)
{
struct us_data *us = (struct us_data *)psh->hostdata[0];
- unsigned long flags;
- int result;
-
- /* lock the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
- /* release the interrupt handler, if necessary */
- if (us->irq_handle) {
- US_DEBUGP("-- releasing irq\n");
- result = usb_release_irq(us->pusb_dev, us->irq_handle,
- us->irqpipe);
- US_DEBUGP("-- usb_release_irq() returned %d\n", result);
- us->irq_handle = NULL;
- }
-
- /* lock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ /* Kill the control threads
+ *
+ * Enqueue the command, wake up the thread, and wait for
+ * notification that it's exited.
+ */
+ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+ us->action = US_ACT_EXIT;
+ up(&(us->sleeper));
+ down(&(us->notify));
+
+ /* free the data structure we were using */
+ US_DEBUGP("-- freeing private host data structure\n");
+ kfree(us);
+ (struct us_data*)psh->hostdata[0] = NULL;
/* we always have a successful release */
return 0;
@@ -1171,20 +1087,38 @@ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
return 0;
}
-/* FIXME: This doesn't actually abort anything */
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
static int us_abort( Scsi_Cmnd *srb )
{
- return 0;
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ US_DEBUGP("us_abort() called\n");
+
+ /* if we're stuck waiting for an IRQ, simulate it */
+ if (us->ip_wanted) {
+ US_DEBUGP("-- simulating missing IRQ\n");
+ up(&(us->ip_waitq));
+ return SUCCESS;
+ }
+
+ return FAILED;
}
/* FIXME: this doesn't do anything right now */
static int us_bus_reset( Scsi_Cmnd *srb )
{
- struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ // struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
US_DEBUGP("Bus reset requested\n");
- if (us->ip_wanted)
- up(&(us->ip_waitq));
// us->transport_reset(us);
return SUCCESS;
}
@@ -1192,6 +1126,7 @@ static int us_bus_reset( Scsi_Cmnd *srb )
/* FIXME: This doesn't actually reset anything */
static int us_host_reset( Scsi_Cmnd *srb )
{
+ printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
return 0;
}
@@ -1209,14 +1144,13 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
struct us_data *us;
char *pos = buffer;
char *tmp_ptr;
- unsigned long flags;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* lock the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/* find our data from hostno */
us = us_list;
@@ -1228,7 +1162,7 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
/* if we couldn't find it, we return an error */
if (!us) {
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
return -ESRCH;
}
@@ -1274,11 +1208,42 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
break;
}
+ SPRINTF(" Transport: ");
+ switch (us->subclass) {
+ case US_SC_RBC:
+ SPRINTF("Reduced Block Commands\n");
+ break;
+
+ case US_SC_8020:
+ SPRINTF("8020i\n");
+ break;
+
+ case US_SC_QIC:
+ SPRINTF("QIC-157\n");
+ break;
+
+ case US_SC_8070:
+ SPRINTF("8070i\n");
+ break;
+
+ case US_SC_SCSI:
+ SPRINTF("Transparent SCSI\n");
+ break;
+
+ case US_SC_UFI:
+ SPRINTF("Uniform Floppy Interface\n");
+ break;
+
+ default:
+ SPRINTF("Unknown Transport\n");
+ break;
+ }
+
/* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
/* release our lock on the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
/*
* Calculate start of next buffer, and return value.
@@ -1298,36 +1263,30 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
*/
static Scsi_Host_Template my_host_template = {
- NULL, /* next */
- NULL, /* module */
- NULL, /* proc_dir */
- usb_stor_proc_info,
- NULL, /* name - points to unique */
- us_detect,
- us_release,
- NULL, /* info */
- NULL, /* ioctl */
- us_command,
- us_queuecommand,
- NULL, /* eh_strategy */
- us_abort,
- us_bus_reset,
- us_bus_reset,
- us_host_reset,
- NULL, /* abort */
- NULL, /* reset */
- NULL, /* slave_attach */
- NULL, /* bios_param */
- NULL, /* select_queue_depths */
- 1, /* can_queue */
- -1, /* this_id */
- SG_ALL, /* sg_tablesize */
- 1, /* cmd_per_lun */
- 0, /* present */
- FALSE, /* unchecked_isa_dma */
- TRUE, /* use_clustering */
- TRUE, /* use_new_eh_code */
- TRUE /* emulated */
+ name: "usb-storage",
+ proc_info: usb_stor_proc_info,
+ info: us_info,
+
+ detect: us_detect,
+ release: us_release,
+ command: us_command,
+ queuecommand: us_queuecommand,
+
+ eh_abort_handler: us_abort,
+ eh_device_reset_handler:us_bus_reset,
+ eh_bus_reset_handler: us_bus_reset,
+ eh_host_reset_handler: us_host_reset,
+
+ can_queue: 1,
+ this_id: -1,
+
+ sg_tablesize: SG_ALL,
+ cmd_per_lun: 1,
+ present: 0,
+ unchecked_isa_dma: FALSE,
+ use_clustering: TRUE,
+ use_new_eh_code: TRUE,
+ emulated: TRUE,
};
static unsigned char sense_notready[] = {
@@ -1362,10 +1321,11 @@ static int usb_stor_control_thread(void * __us)
*/
daemonize();
- sprintf(current->comm, "usbscsi%d", us->host_number);
+ sprintf(current->comm, "usb-storage-%d", us->host_number);
unlock_kernel();
+ /* signal that we've started the thread */
up(&(us->notify));
for(;;) {
@@ -1382,14 +1342,10 @@ static int usb_stor_control_thread(void * __us)
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
- /* FIXME: we need to examine placment of break; and
- * scsi_done() calls */
-
switch (action) {
case US_ACT_COMMAND:
/* bad device */
- /* FIXME: we need to enable and test multiple LUNs */
- if (us->srb->target || us->srb->lun) {
+ if (us->srb->target) {
US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
us->srb->result = DID_BAD_TARGET << 16;
@@ -1399,6 +1355,9 @@ static int usb_stor_control_thread(void * __us)
break;
}
+ /* lock the device pointers */
+ down(&(us->dev_semaphore));
+
/* our device has gone - pretend not ready */
/* FIXME: we also need to handle INQUIRY here,
* probably */
@@ -1414,6 +1373,10 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = (DID_OK << 16) | 2;
}
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1434,6 +1397,11 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
+
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1453,11 +1421,15 @@ static int usb_stor_control_thread(void * __us)
} /* end switch on action */
/* exit if we get a signal to exit */
- if (action == US_ACT_EXIT)
+ if (action == US_ACT_EXIT) {
+ US_DEBUGP("-- US_ACT_EXIT command recieved\n");
break;
+ }
} /* for (;;) */
- printk("usb_stor_control_thread exiting\n");
+ /* notify the exit routine that we're actually exiting now */
+ up(&(us->notify));
+
return 0;
}
@@ -1471,7 +1443,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
struct us_data *ss = NULL;
GUID(guid); /* Global Unique Identifier */
int result;
- unsigned long flags;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
@@ -1531,9 +1502,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
&ss->irq_handle);
if (result < 0)
return NULL;
-
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
}
/*
@@ -1613,7 +1581,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
/* lock access to the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/*
* Now check if we have seen this GUID before
@@ -1655,7 +1623,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
@@ -1664,6 +1632,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX(&(ss->queue_exclusion));
+ init_MUTEX(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */
ss->subclass = subclass;
@@ -1725,7 +1694,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
break;
case US_SC_QIC:
- US_DEBUGPX("QIC157\n");
+ US_DEBUGPX("QIC-157\n");
break;
case US_SC_8070:
@@ -1774,9 +1743,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Grab the next host number */
ss->host_number = my_host_number++;
- /* FIXME: this is bad. We abuse this pointer so we
- * can pass the ss pointer to the host controler thread
- * in us_detect
+ /* We abuse this pointer so we can pass the ss pointer to
+ * the host controler thread in us_detect. But how else are
+ * we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
@@ -1795,7 +1764,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
down(&(ss->notify));
/* now register - our detect function will be called */
- ss->htmplt.module = &__this_module;
+ ss->htmplt.module = THIS_MODULE;
scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
/* put us in the list */
@@ -1804,7 +1773,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
/* release the data structure lock */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
@@ -1829,6 +1798,9 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
return;
}
+ /* lock access to the device data structure */
+ down(&(ss->dev_semaphore));
+
/* release the IRQ, if we have one */
if (ss->irq_handle) {
US_DEBUGP("-- releasing irq handle\n");
@@ -1840,6 +1812,9 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
/* mark the device as gone */
ss->pusb_dev = NULL;
+
+ /* lock access to the device data structure */
+ up(&(ss->dev_semaphore));
}
@@ -1849,18 +1824,10 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void)
{
- /*
- * Check to see if the host template is a different size from
- * what we're expected -- people have updated this in the past
- * and forgotten about this driver.
- */
- if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
- printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n");
- printk(KERN_ERR
- "usb-storage: expected %d bytes, got %d bytes\n",
- SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
- return -1 ;
- }
+ /* initialize internal global data elements */
+ us_list = NULL;
+ init_MUTEX(&us_list_semaphore);
+ my_host_number = 0;
/* register the driver, return -1 if error */
if (usb_register(&storage_driver) < 0)
@@ -1873,36 +1840,38 @@ int __init usb_stor_init(void)
void __exit usb_stor_exit(void)
{
- static struct us_data *ptr;
- static struct us_data *next;
- unsigned long flags;
+ struct us_data *next;
- /*
- * deregister the driver -- this eliminates races with probes and
- * disconnects
+ US_DEBUGP("usb_stor_exit() called\n");
+
+ /* Deregister the driver
+ * This eliminates races with probes and disconnects
*/
+ US_DEBUGP("-- calling usb_deregister()\n");
usb_deregister(&storage_driver) ;
/* lock access to the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
-
- /* unregister all the virtual hosts */
- for (ptr = us_list; ptr != NULL; ptr = ptr->next)
- scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
-
- /* kill the threads */
- /* FIXME: we can do this by sending them a signal to die */
-
- /* free up the data structures */
- /* FIXME: we need to eliminate the host structure also */
- while (ptr) {
- next = ptr->next;
- kfree(ptr);
- ptr = next;
+ down(&us_list_semaphore);
+
+ /* While there are still virtual hosts, unregister them
+ *
+ * Note that the us_release() routine will destroy the local data
+ * structure. So we have to peel these off the top of the list
+ * and keep updating the head pointer as we go.
+ */
+ while (us_list) {
+ /* keep track of where the next one is */
+ next = us_list->next;
+
+ US_DEBUGP("-- calling scsi_unregister_module()\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+ /* advance the list pointer */
+ us_list = next;
}
/* unlock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
}
module_init(usb_stor_init) ;
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 06e6d958b..6a37924ca 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -129,8 +129,8 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri
}
/* Flag definitions */
-#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */
-#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */
+#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */
+#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */
#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for
- Win/MacOS compatibility */
-
+ Win/MacOS compatibility */
+#define US_FL_CBI_AS_CB 0x00000008 /* treat a CBI dev as a CB dev */
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index f77296d7f..b9c09f0d8 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.222 2000/03/13 21:18:02 fliegl Exp $
+ * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
*/
#include <linux/config.h>
@@ -50,6 +50,8 @@
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
+#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+
#include <linux/usb.h>
#include "usb-uhci.h"
#include "usb-uhci-debug.h"
@@ -116,6 +118,26 @@ void clean_descs(uhci_t *s, int force)
}
}
/*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+ if (!list_empty(&s->urb_unlinked)) {
+ s->td1ms->hw.td.status |= TD_CTRL_IOC;
+ }
+ else {
+ s->td1ms->hw.td.status &= ~TD_CTRL_IOC;
+ }
+
+ if (s->timeout_urbs) {
+ s->td32ms->hw.td.status |= TD_CTRL_IOC;
+ }
+ else {
+ s->td32ms->hw.td.status &= ~TD_CTRL_IOC;
+ }
+
+ wmb();
+}
+/*-------------------------------------------------------------------*/
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
_static void enable_desc_loop(uhci_t *s, urb_t *urb)
{
@@ -162,6 +184,9 @@ _static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
#endif
((urb_priv_t*)urb->hcpriv)->started=jiffies;
list_add (p, &s->urb_list);
+ if (urb->timeout)
+ s->timeout_urbs++;
+ uhci_switch_timer_int(s);
}
/*-------------------------------------------------------------------*/
_static void queue_urb (uhci_t *s, urb_t *urb)
@@ -185,6 +210,9 @@ _static void dequeue_urb (uhci_t *s, urb_t *urb)
#endif
list_del (&urb->urb_list);
+ if (urb->timeout && s->timeout_urbs)
+ s->timeout_urbs--;
+
}
/*-------------------------------------------------------------------*/
_static int alloc_td (uhci_desc_t ** new, int flags)
@@ -439,6 +467,13 @@ _static void cleanup_skel (uhci_t *s)
clean_descs(s,1);
+
+ if (s->td32ms) {
+
+ unlink_td(s,s->td32ms,1);
+ delete_desc(s->td32ms);
+ }
+
for (n = 0; n < 8; n++) {
td = s->int_chain[n];
clean_td_chain (td);
@@ -531,8 +566,9 @@ _static int init_skel (uhci_t *s)
if (ret)
goto init_skel_cleanup;
- fill_td (td, TD_CTRL_IOC, 0, 0); // generate 1ms interrupt
+ fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
insert_td (s, qh, td, 0);
+ s->td1ms=td;
dbg("allocating qh: bulk_chain");
ret = alloc_qh (&qh);
@@ -597,6 +633,16 @@ _static int init_skel (uhci_t *s)
((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
}
+ ret = alloc_td (&td, 0);
+
+ if (ret)
+ goto init_skel_cleanup;
+
+ fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt
+ s->td32ms=td;
+
+ insert_td_horizontal (s, s->int_chain[5], td);
+
mb();
//uhci_show_queue(s->control_chain);
dbg("init_skel exit");
@@ -995,6 +1041,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
if (urb->status == -EINPROGRESS) {
// URB probably still in work
dequeue_urb (s, urb);
+ uhci_switch_timer_int(s);
s->unlink_urb_done=1;
spin_unlock_irqrestore (&s->urb_list_lock, flags);
@@ -1125,9 +1172,11 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
if (urb->status == -EINPROGRESS) {
((urb_priv_t*)urb->hcpriv)->started = ~0;
+
dequeue_urb (s, urb);
list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
+ uhci_switch_timer_int(s);
+
s->unlink_urb_done = 1;
urb->status = -ECONNABORTED; // mark urb as "waiting to be killed"
@@ -1495,7 +1544,7 @@ _static int uhci_submit_urb (urb_t *urb)
(!(urb->transfer_flags & USB_QUEUE_BULK) || !(bulk_urb->transfer_flags & USB_QUEUE_BULK)))) {
spin_unlock_irqrestore (&s->urb_list_lock, flags);
usb_dec_dev_use (urb->dev);
- err("ENXIO1 %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
+ err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
return -ENXIO; // urb already queued
}
}
@@ -1599,6 +1648,7 @@ _static void uhci_check_timeouts(uhci_t *s)
#endif
}
+ s->timeout_check=jiffies;
}
/*-------------------------------------------------------------------
@@ -1922,7 +1972,7 @@ _static int rh_submit_urb (urb_t *urb)
OK (len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff,
- uhci->io_addr, "UHCI",
+ uhci->io_addr, "UHCI",
data, wLength);
if (len > 0) {
OK (min (leni, len));
@@ -2481,15 +2531,15 @@ restart:
goto restart;
}
}
- if ((s->frame_counter & 63) == 0)
+ if ((jiffies - s->timeout_check) > (HZ/30))
uhci_check_timeouts(s);
clean_descs(s,0);
uhci_cleanup_unlink(s, 0);
-
+ uhci_switch_timer_int(s);
+
spin_unlock (&s->urb_list_lock);
- s->frame_counter++;
outw (status, io_addr + USBSTS);
//dbg("uhci_interrupt: done");
@@ -2630,12 +2680,14 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
spin_lock_init (&s->qh_lock);
spin_lock_init (&s->td_lock);
atomic_set(&s->avoid_bulk, 0);
+ s->timeout_urbs = 0;
s->irq = -1;
s->io_addr = io_addr;
s->io_size = io_size;
s->next = devs; //chain new uhci device into global list
- s->frame_counter = 0;
-
+ s->timeout_check = 0;
+ s->uhci_pci=dev;
+
bus = usb_alloc_bus (&uhci_device_operations);
if (!bus) {
kfree (s);
@@ -2739,6 +2791,7 @@ _static int __init start_uhci (struct pci_dev *dev)
info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
}
+
return alloc_uhci(dev, dev->irq, io_addr, io_size);
}
return -1;
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
index 93173f2c2..3c5717d1e 100644
--- a/drivers/usb/usb-uhci.h
+++ b/drivers/usb/usb-uhci.h
@@ -2,10 +2,9 @@
#define __LINUX_UHCI_H
/*
- $Id: usb-uhci.h,v 1.50 2000/03/13 21:18:04 fliegl Exp $
+ $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
*/
#define MODNAME "usb-uhci"
-#define VERSTR "$Revision: 1.50 $ time " __TIME__ " " __DATE__
#define UHCI_LATENCY_TIMER 0
static __inline__ void uhci_wait_ms(unsigned int ms)
@@ -202,6 +201,8 @@ typedef struct uhci {
uhci_desc_t *control_chain;
uhci_desc_t *bulk_chain;
uhci_desc_t *chain_end;
+ uhci_desc_t *td1ms;
+ uhci_desc_t *td32ms;
struct list_head free_desc;
spinlock_t qh_lock;
spinlock_t td_lock;
@@ -209,7 +210,9 @@ typedef struct uhci {
int loop_usage; // URBs using bandwidth reclamation
struct list_head urb_unlinked; // list of all unlinked urbs
- int frame_counter;
+ long timeout_check;
+ int timeout_urbs;
+ struct pci_dev *uhci_pci;
} uhci_t, *puhci_t;
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 9b2d38b6f..8f962b485 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -24,7 +24,11 @@
#include <linux/bitops.h>
#include <linux/malloc.h>
#include <linux/interrupt.h> /* for in_interrupt() */
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
/*
@@ -1080,7 +1084,7 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor
int size;
struct usb_descriptor_header *header;
- memcpy(config, buffer, USB_DT_INTERFACE_SIZE);
+ memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
@@ -1419,32 +1423,28 @@ int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
static void usb_set_maxpacket(struct usb_device *dev)
{
- int i, j, b;
- struct usb_interface *ifp;
+ int i, b;
for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
- ifp = dev->actconfig->interface + i;
-
- for (j = 0; j < ifp->num_altsetting; j++) {
- struct usb_interface_descriptor *as = ifp->altsetting + j;
- struct usb_endpoint_descriptor *ep = as->endpoint;
- int e;
-
- for (e=0; e<as->bNumEndpoints; e++) {
- b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
+ struct usb_interface *ifp = dev->actconfig->interface + i;
+ struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
+ struct usb_endpoint_descriptor *ep = as->endpoint;
+ int e;
+
+ for (e=0; e<as->bNumEndpoints; e++) {
+ b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
+ dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+ dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
+ }
+ else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
+ if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+ }
+ else {
+ if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
- }
- else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
- if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
- dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
- }
- else {
- if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
- dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
- }
}
}
}
@@ -1512,6 +1512,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
return ret;
iface->act_altsetting = alternate;
+ dev->toggle[0] = 0; /* 9.1.1.5 says to do this */
+ dev->toggle[1] = 0;
usb_set_maxpacket(dev);
return 0;
}
@@ -1624,7 +1626,7 @@ int usb_get_configuration(struct usb_device *dev)
err("config descriptor too short (expected %i, got %i)",tmp,result);
kfree(bigbuffer);
goto err;
- }
+ }
result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
kfree(bigbuffer);
@@ -1638,8 +1640,8 @@ int usb_get_configuration(struct usb_device *dev)
}
return 0;
- err:
- dev->descriptor.bNumConfigurations=cfgno;
+err:
+ dev->descriptor.bNumConfigurations = cfgno;
return result;
}
@@ -1674,7 +1676,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
/* always use the first langid listed */
- info("USB device number %d default language ID 0x%x",
+ dbg("USB device number %d default language ID 0x%x",
dev->devnum, dev->string_langid);
}
}
@@ -1789,14 +1791,16 @@ int usb_new_device(struct usb_device *dev)
return -1;
}
- info("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
+ dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+#ifdef DEBUG
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iProduct)
usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+#endif
/* now that the basic setup is over, add a /proc/bus/usb entry */
usbdevfs_add_device(dev);
@@ -1874,6 +1878,7 @@ EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_init_root_hub);
EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
EXPORT_SYMBOL(usb_release_bandwidth);
diff --git a/drivers/usb/usbdevice_fs.h b/drivers/usb/usbdevice_fs.h
deleted file mode 100644
index 95eaa937a..000000000
--- a/drivers/usb/usbdevice_fs.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*****************************************************************************/
-
-/*
- * usbdevice_fs.h -- USB device file system.
- *
- * Copyright (C) 2000
- * Thomas Sailer (sailer@ife.ee.ethz.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 distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- * 0.1 04.01.2000 Created
- *
- * $Id: usbdevice_fs.h,v 1.1 2000/01/06 18:40:41 tom Exp $
- */
-
-/*****************************************************************************/
-
-#ifndef _LINUX_USBDEVICE_FS_H
-#define _LINUX_USBDEVICE_FS_H
-
-/* --------------------------------------------------------------------- */
-
-#define USBDEVICE_SUPER_MAGIC 0x9fa2
-
-/* usbdevfs ioctl codes */
-
-struct usbdevfs_ctrltransfer {
- __u8 requesttype;
- __u8 request;
- __u16 value;
- __u16 index;
- __u16 length;
- __u32 timeout; /* in milliseconds */
- void *data;
-};
-
-struct usbdevfs_bulktransfer {
- unsigned int ep;
- unsigned int len;
- unsigned int timeout; /* in milliseconds */
- void *data;
-};
-
-struct usbdevfs_setinterface {
- unsigned int interface;
- unsigned int altsetting;
-};
-
-struct usbdevfs_disconnectsignal {
- unsigned int signr;
- void *context;
-};
-
-#define USBDEVFS_URB_DISABLE_SPD 1
-#define USBDEVFS_URB_ISO_ASAP 2
-
-#define USBDEVFS_URB_TYPE_ISO 0
-#define USBDEVFS_URB_TYPE_INTERRUPT 1
-#define USBDEVFS_URB_TYPE_CONTROL 2
-#define USBDEVFS_URB_TYPE_BULK 3
-
-struct usbdevfs_iso_packet_desc {
- unsigned int length;
- unsigned int actual_length;
- unsigned int status;
-};
-
-struct usbdevfs_urb {
- unsigned char type;
- unsigned char endpoint;
- int status;
- unsigned int flags;
- void *buffer;
- int buffer_length;
- int actual_length;
- int start_frame;
- int number_of_packets;
- int error_count;
- unsigned int signr; /* signal to be sent on error, -1 if none should be sent */
- void *usercontext;
- struct usbdevfs_iso_packet_desc iso_frame_desc[0];
-};
-
-#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
-#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer)
-#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)
-#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface)
-#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
-#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
-#define USBDEVFS_DISCARDURB _IO('U', 11)
-#define USBDEVFS_REAPURB _IOW('U', 12, void *)
-#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)
-#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal)
-#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
-#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
-
-/* --------------------------------------------------------------------- */
-
-#ifdef __KERNEL__
-
-#include <linux/list.h>
-#include <asm/semaphore.h>
-
-/*
- * inode number macros
- */
-#define ITYPE(x) ((x)&(0xf<<28))
-#define ISPECIAL (0<<28)
-#define IBUS (1<<28)
-#define IDEVICE (2<<28)
-#define IBUSNR(x) (((x)>>8)&0xff)
-#define IDEVNR(x) ((x)&0xff)
-
-#define IROOT 1
-
-/*
- * sigh. rwsemaphores do not (yet) work from modules
- */
-
-#define rw_semaphore semaphore
-#define init_rwsem init_MUTEX
-#define down_read down
-#define down_write down
-#define up_read up
-#define up_write up
-
-
-struct dev_state {
- struct list_head list; /* state list */
- struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */
- struct usb_device *dev;
- struct file *file;
- spinlock_t lock; /* protects the async urb lists */
- struct list_head async_pending;
- struct list_head async_completed;
- wait_queue_head_t wait; /* wake up if a request completed */
- unsigned int discsignr;
- struct task_struct *disctask;
- void *disccontext;
- unsigned long ifclaimed;
-};
-
-/* internal methods & data */
-extern struct usb_driver usbdevfs_driver;
-extern struct file_operations usbdevfs_drivers_fops;
-extern struct file_operations usbdevfs_devices_fops;
-extern struct file_operations usbdevfs_device_file_operations;
-extern struct inode_operations usbdevfs_device_inode_operations;
-extern struct inode_operations usbdevfs_bus_inode_operations;
-extern struct file_operations usbdevfs_bus_file_operations;
-extern void usbdevfs_conn_disc_event(void);
-
-
-#endif /* __KERNEL__ */
-
-/* --------------------------------------------------------------------- */
-#endif /* _LINUX_USBDEVICE_FS_H */