diff options
Diffstat (limited to 'drivers/usb')
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 (®s->revision) & 0xff; + if (temp != 0x10) + dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + + temp = readl (®s->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 (®s->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 (®s->intrstatus)); + ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); + // intrdisable always same as intrenable + // ohci_dump_intr_mask ("intrdisable", readl (®s->intrdisable)); + + maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); + + maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); + maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); + + maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); + maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); + + maybe_print_eds ("donehead", readl (®s->donehead)); +} + +static void ohci_dump_roothub (ohci_t *controller, int verbose) +{ + struct ohci_regs *regs = controller->regs; + __u32 temp, ndp, i; + + temp = readl (®s->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 (®s->roothub.b); + dbg ("roothub.b: %08x PPCM=%04x DR=%04x", + temp, + (temp & RH_B_PPCM) >> 16, + (temp & RH_B_DR) + ); + temp = readl (®s->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 (®s->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 */ |