changeset 903:a9ef93192894

6314504 Support for Prolific USB serial adapters
author xs156463
date Mon, 14 Nov 2005 02:38:25 -0800
parents eda97dc69bb7
children 4f885c862682
files usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNWuprl/Makefile usr/src/pkgdefs/SUNWuprl/depend usr/src/pkgdefs/SUNWuprl/pkginfo.tmpl usr/src/pkgdefs/SUNWuprl/postinstall usr/src/pkgdefs/SUNWuprl/preremove usr/src/pkgdefs/SUNWuprl/prototype_com usr/src/pkgdefs/SUNWuprl/prototype_i386 usr/src/pkgdefs/SUNWuprl/prototype_sparc usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/usb/clients/usbser/usbsprl/pl2303_dsd.c usr/src/uts/common/io/usb/clients/usbser/usbsprl/usbser_pl2303.c usr/src/uts/common/sys/usb/clients/usbser/usbsprl/pl2303_var.h usr/src/uts/common/sys/usb/clients/usbser/usbsprl/pl2303_vendor.h usr/src/uts/intel/Makefile.intel usr/src/uts/intel/usbsprl/Makefile usr/src/uts/sparc/Makefile.sparc usr/src/uts/sparc/usbsprl/Makefile usr/src/uts/sparc/usbsprl/usbsprl.wlcmd usr/src/uts/sparc/usbsprl/usbsprl_with_usba.wlcmd usr/src/uts/sparc/warlock/Makefile
diffstat 22 files changed, 3571 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/Makefile	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/pkgdefs/Makefile	Mon Nov 14 02:38:25 2005 -0800
@@ -310,6 +310,7 @@
 	SUNWuksp \
 	SUNWugen \
 	SUNWugenu \
+	SUNWuprl \
 	SUNWusb \
 	SUNWusbs \
 	SUNWusbu \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/Makefile	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+ 
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(FILES) depend postinstall preremove
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/depend	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,54 @@
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+P SUNWusb	USB Device Drivers
+P SUNWusbs	USB generic serial module 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/pkginfo.tmpl	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,48 @@
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWuprl"
+NAME="Prolific PL2303 USB-to-serial driver"
+ARCH="ISA"
+CATEGORY="system"
+BASEDIR=/
+SUNW_PKGTYPE="root"
+CLASSES="none"
+DESC="Prolific PL2303 USB-to-serial driver"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+VERSION="ONVERS,REV=0.0.0"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+MAXINST="1000"
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/postinstall	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+ 
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+installed() {
+	driver=$1
+	grep "^${driver} " $BASEDIR/etc/name_to_major > /dev/null 2>&1
+
+	return $?
+}
+
+EXIT=0
+
+USBSPRL_ALIASES="\"usb67b,2303\""
+
+if installed usbsprl ; then
+	echo "usbsprl already installed" || EXIT 1
+
+else
+	add_drv -b ${BASEDIR} -m '* 0666 root sys' \
+	    -i "${USBSPRL_ALIASES}" -n usbsprl || \
+	    EXIT=1
+fi
+
+exit $EXIT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/preremove	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,40 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+ 
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+EXIT=0
+
+if grep -w usbsprl ${BASEDIR}/etc/name_to_major > /dev/null 2>&1
+then
+	rem_drv -b ${BASEDIR} usbsprl || EXIT=1
+fi
+
+exit $EXIT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/prototype_com	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# SUNWuprl
+#
+i copyright
+i depend
+i pkginfo
+i postinstall
+i preremove
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/prototype_i386	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWuprl
+#
+f none kernel/drv/usbsprl 0755 root sys
+d none kernel/drv/amd64 0755 root sys
+f none kernel/drv/amd64/usbsprl 0755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWuprl/prototype_sparc	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWuprl
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/usbsprl 0755 root sys
--- a/usr/src/uts/common/Makefile.files	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/uts/common/Makefile.files	Mon Nov 14 02:38:25 2005 -0800
@@ -588,6 +588,8 @@
 
 USBSER_KEYSPAN_OBJS += usbser_keyspan.o keyspan_dsd.o keyspan_pipe.o
 
+USBSPRL_OBJS += usbser_pl2303.o pl2303_dsd.o
+
 WC_OBJS += wscons.o
 
 SCSI_OBJS +=	scsi_capabilities.o	scsi_control.o	scsi_watch.o \
--- a/usr/src/uts/common/Makefile.rules	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/uts/common/Makefile.rules	Mon Nov 14 02:38:25 2005 -0800
@@ -688,6 +688,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/usb/clients/usbser/usbsprl/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/usb/hcd/openhci/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1391,6 +1395,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/clients/usbser/usbser_keyspan/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/clients/usbser/usbsprl/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/hcd/openhci/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/usb/clients/usbser/usbsprl/pl2303_dsd.c	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,2139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ *
+ * USB Prolific PL2303 device-specific driver (DSD)
+ *
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/termio.h>
+#include <sys/termiox.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#define	USBDRV_MAJOR_VER	2
+#define	USBDRV_MINOR_VER	0
+
+#include <sys/usb/usba.h>
+#include <sys/usb/usba/usba_types.h>
+#include <sys/usb/usba/usba_impl.h>
+
+#include <sys/usb/clients/usbser/usbser_dsdi.h>
+#include <sys/usb/clients/usbser/usbsprl/pl2303_var.h>
+#include <sys/usb/clients/usbser/usbsprl/pl2303_vendor.h>
+
+
+/*
+ * DSD operations
+ */
+static int	pl2303_attach(ds_attach_info_t *);
+static void	pl2303_detach(ds_hdl_t);
+static int	pl2303_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
+static void	pl2303_unregister_cb(ds_hdl_t, uint_t);
+static int	pl2303_open_port(ds_hdl_t, uint_t);
+static int	pl2303_close_port(ds_hdl_t, uint_t);
+
+/* power management */
+static int	pl2303_usb_power(ds_hdl_t, int, int, int *);
+static int	pl2303_suspend(ds_hdl_t);
+static int	pl2303_resume(ds_hdl_t);
+static int	pl2303_disconnect(ds_hdl_t);
+static int	pl2303_reconnect(ds_hdl_t);
+
+/* standard UART operations */
+static int	pl2303_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
+static int	pl2303_set_modem_ctl(ds_hdl_t, uint_t, int, int);
+static int	pl2303_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
+static int	pl2303_break_ctl(ds_hdl_t, uint_t, int);
+
+/* data xfer */
+static int	pl2303_tx(ds_hdl_t, uint_t, mblk_t *);
+static mblk_t	*pl2303_rx(ds_hdl_t, uint_t);
+static void	pl2303_stop(ds_hdl_t, uint_t, int);
+static void	pl2303_start(ds_hdl_t, uint_t, int);
+static int	pl2303_fifo_flush(ds_hdl_t, uint_t, int);
+static int	pl2303_fifo_drain(ds_hdl_t, uint_t, int);
+
+
+/*
+ * Sub-routines
+ */
+
+/* configuration routines */
+static void	pl2303_cleanup(pl2303_state_t *, int);
+static int	pl2303_dev_attach(pl2303_state_t *);
+static int	pl2303_open_hw_port(pl2303_state_t *);
+
+/* hotplug */
+static int	pl2303_restore_device_state(pl2303_state_t *);
+static int	pl2303_restore_port_state(pl2303_state_t *);
+
+/* power management */
+static int	pl2303_create_pm_components(pl2303_state_t *);
+static void	pl2303_destroy_pm_components(pl2303_state_t *);
+static int	pl2303_pm_set_busy(pl2303_state_t *);
+static void	pl2303_pm_set_idle(pl2303_state_t *);
+static int	pl2303_pwrlvl0(pl2303_state_t *);
+static int	pl2303_pwrlvl1(pl2303_state_t *);
+static int	pl2303_pwrlvl2(pl2303_state_t *);
+static int	pl2303_pwrlvl3(pl2303_state_t *);
+
+/* pipe operations */
+static int	pl2303_open_pipes(pl2303_state_t *);
+static void	pl2303_close_pipes(pl2303_state_t *);
+static void	pl2303_disconnect_pipes(pl2303_state_t *);
+static int	pl2303_reconnect_pipes(pl2303_state_t *);
+
+/* pipe callbacks */
+void		pl2303_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
+void		pl2303_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
+
+/* data transfer routines */
+static int	pl2303_rx_start(pl2303_state_t *);
+static void	pl2303_tx_start(pl2303_state_t *, int *);
+static int	pl2303_send_data(pl2303_state_t *, mblk_t *);
+static int	pl2303_wait_tx_drain(pl2303_state_t *, int);
+
+/* vendor-specific commands */
+static int	pl2303_cmd_get_line(pl2303_state_t *, mblk_t **);
+static int	pl2303_cmd_set_line(pl2303_state_t *, mblk_t *);
+static int	pl2303_cmd_set_ctl(pl2303_state_t *, uint8_t);
+static int	pl2303_cmd_vendor_write0(pl2303_state_t *, uint16_t, int16_t);
+static int	pl2303_cmd_set_rtscts(pl2303_state_t *);
+static int	pl2303_cmd_break(pl2303_state_t *, int);
+static void	pl2303_mctl2reg(int mask, int val, uint8_t *);
+static int	pl2303_reg2mctl(uint8_t);
+
+/* misc */
+static void	pl2303_put_tail(mblk_t **, mblk_t *);
+static void	pl2303_put_head(mblk_t **, mblk_t *);
+
+
+/*
+ * DSD ops structure
+ */
+ds_ops_t ds_ops = {
+	DS_OPS_VERSION,
+	pl2303_attach,
+	pl2303_detach,
+	pl2303_register_cb,
+	pl2303_unregister_cb,
+	pl2303_open_port,
+	pl2303_close_port,
+	pl2303_usb_power,
+	pl2303_suspend,
+	pl2303_resume,
+	pl2303_disconnect,
+	pl2303_reconnect,
+	pl2303_set_port_params,
+	pl2303_set_modem_ctl,
+	pl2303_get_modem_ctl,
+	pl2303_break_ctl,
+	NULL,			/* HW don't support loopback */
+	pl2303_tx,
+	pl2303_rx,
+	pl2303_stop,
+	pl2303_start,
+	pl2303_fifo_flush,
+	pl2303_fifo_drain
+};
+
+
+/*
+ * baud code into baud rate
+ * value 0 means not supported in hardware
+ *
+ */
+static int pl2303_speedtab[] = {
+	0,	/* B0 */
+	0,	/* B50 */
+	75,	/* B75 */
+	0,	/* B110 */
+	0,	/* B134 */
+	150,	/* B150 */
+	0,	/* B200 */
+	300,	/* B300 */
+	600,	/* B600 */
+	1200,	/* B1200 */
+	1800,	/* B1800 */
+	2400,	/* B2400 */
+	4800,	/* B4800 */
+	9600,	/* B9600 */
+	19200,	/* B19200 */
+	38400,	/* B38400 */
+	57600,	/* B57600 */
+	0,	/* B76800 */
+	115200,	/* B115200 */
+	0,	/* B153600 */
+	230400,	/* B230400 */
+	0,	/* B307200 */
+	460800	/* B460800 */
+};
+
+
+/* debug support */
+static uint_t   pl2303_errlevel = USB_LOG_L4;
+static uint_t   pl2303_errmask = DPRINT_MASK_ALL;
+static uint_t   pl2303_instance_debug = (uint_t)-1;
+
+
+/*
+ * ds_attach
+ */
+static int
+pl2303_attach(ds_attach_info_t *aip)
+{
+	pl2303_state_t	*plp;
+
+	plp = (pl2303_state_t *)kmem_zalloc(sizeof (pl2303_state_t), KM_SLEEP);
+	plp->pl_dip = aip->ai_dip;
+	plp->pl_usb_events = aip->ai_usb_events;
+	*aip->ai_hdl = (ds_hdl_t)plp;
+
+	/* only one port */
+	*aip->ai_port_cnt = 1;
+
+	if (usb_client_attach(plp->pl_dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
+		pl2303_cleanup(plp, 1);
+
+		return (USB_FAILURE);
+	}
+
+	if (usb_get_dev_data(plp->pl_dip, &plp->pl_dev_data,  USB_PARSE_LVL_IF,
+	    0) != USB_SUCCESS) {
+		pl2303_cleanup(plp, 2);
+
+		return (USB_FAILURE);
+	}
+
+	/*
+	 * check the chip type: pl2303_H, pl2303_X (or pl2303_HX)
+	 * pl2303_UNKNOWN means not supported chip type
+	 */
+	if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_H) {
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_chiptype = pl2303_H;
+		mutex_exit(&plp->pl_mutex);
+		USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh,
+			"Chip Type: pl2303_H");
+	} else if (plp->pl_dev_data->dev_descr->bcdDevice == PROLIFIC_REV_X) {
+		/*
+		 * pl2303_HX and pl2303_X devices have different hardware,
+		 * but from the view of device driver, they have the same
+		 * software interface.
+		 *
+		 * so "pl2303_X" will stand for both pl2303_HX and pl2303_X
+		 * devices in this driver
+		 */
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_chiptype = pl2303_X;
+		mutex_exit(&plp->pl_mutex);
+		USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh,
+			"Chip Type: pl2303_HX or pl2303_X");
+	} else {
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_chiptype = pl2303_UNKNOWN;
+		mutex_exit(&plp->pl_mutex);
+		USB_DPRINTF_L4(DPRINT_ATTACH, plp->pl_lh,
+			"Chip Type: Unknown");
+	}
+
+	plp->pl_lh = usb_alloc_log_hdl(plp->pl_dip, "pl2303",
+	    &pl2303_errlevel, &pl2303_errmask, &pl2303_instance_debug, 0);
+
+	plp->pl_def_ph = plp->pl_dev_data->dev_default_ph;
+
+	mutex_init(&plp->pl_mutex, NULL, MUTEX_DRIVER,
+			plp->pl_dev_data->dev_iblock_cookie);
+
+	cv_init(&plp->pl_tx_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&plp->pl_rx_cv, NULL, CV_DRIVER, NULL);
+
+	mutex_enter(&plp->pl_mutex);
+	plp->pl_dev_state = USB_DEV_ONLINE;
+	plp->pl_port_state = PL2303_PORT_CLOSED;
+	mutex_exit(&plp->pl_mutex);
+
+	if (pl2303_create_pm_components(plp) != USB_SUCCESS) {
+		pl2303_cleanup(plp, 2);
+
+		return (USB_FAILURE);
+	}
+
+	if (usb_register_event_cbs(plp->pl_dip, plp->pl_usb_events, 0)
+	    != USB_SUCCESS) {
+		pl2303_cleanup(plp, 3);
+
+		return (USB_FAILURE);
+	}
+
+	if (usb_pipe_get_max_bulk_transfer_size(plp->pl_dip,
+	    &plp->pl_xfer_sz) != USB_SUCCESS) {
+		pl2303_cleanup(plp, 4);
+
+		return (USB_FAILURE);
+	}
+
+	if (plp->pl_xfer_sz > PL2303_XFER_SZ_MAX) {
+		plp->pl_xfer_sz = PL2303_XFER_SZ_MAX;
+	}
+
+	if (pl2303_dev_attach(plp) != USB_SUCCESS) {
+		pl2303_cleanup(plp, 4);
+
+		return (USB_FAILURE);
+	}
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_detach
+ */
+static void
+pl2303_detach(ds_hdl_t hdl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	pl2303_cleanup(plp, PL2303_CLEANUP_LEVEL_MAX);
+}
+
+
+/*
+ * ds_register_cb
+ */
+/*ARGSUSED*/
+static int
+pl2303_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	plp->pl_cb = *cb;
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_unregister_cb
+ */
+/*ARGSUSED*/
+static void
+pl2303_unregister_cb(ds_hdl_t hdl, uint_t port_num)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	bzero(&plp->pl_cb, sizeof (plp->pl_cb));
+}
+
+
+/*
+ * ds_open_port
+ */
+/*ARGSUSED*/
+static int
+pl2303_open_port(ds_hdl_t hdl, uint_t port_num)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		rval = USB_FAILURE;
+
+	USB_DPRINTF_L4(DPRINT_OPEN, plp->pl_lh, "pl2303_open_port");
+
+	mutex_enter(&plp->pl_mutex);
+	if ((plp->pl_dev_state == USB_DEV_DISCONNECTED) ||
+	    (plp->pl_port_state != PL2303_PORT_CLOSED)) {
+		mutex_exit(&plp->pl_mutex);
+
+		return (rval);
+	}
+
+	mutex_exit(&plp->pl_mutex);
+
+	if ((rval = pl2303_pm_set_busy(plp)) != USB_SUCCESS) {
+
+		return (rval);
+	}
+
+	/* initialize hardware serial port */
+	rval = pl2303_open_hw_port(plp);
+
+	if (rval == USB_SUCCESS) {
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_port_state = PL2303_PORT_OPEN;
+
+		/* start to receive data */
+		(void) pl2303_rx_start(plp);
+		mutex_exit(&plp->pl_mutex);
+	} else {
+		pl2303_pm_set_idle(plp);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * ds_close_port
+ */
+/*ARGSUSED*/
+static int
+pl2303_close_port(ds_hdl_t hdl, uint_t port_num)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CLOSE, plp->pl_lh, "pl2303_close_port");
+
+	mutex_enter(&plp->pl_mutex);
+
+	/* free resources and finalize state */
+	if (plp->pl_rx_mp) {
+		freemsg(plp->pl_rx_mp);
+		plp->pl_rx_mp = NULL;
+	}
+	if (plp->pl_tx_mp) {
+		freemsg(plp->pl_tx_mp);
+		plp->pl_tx_mp = NULL;
+	}
+
+	plp->pl_port_state = PL2303_PORT_CLOSED;
+	mutex_exit(&plp->pl_mutex);
+
+	pl2303_pm_set_idle(plp);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * power management
+ * ----------------
+ *
+ * ds_usb_power
+ */
+/*ARGSUSED*/
+static int
+pl2303_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	pl2303_pm_t	*pm = plp->pl_pm;
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_usb_power");
+
+	if (!pm) {
+
+		return (USB_FAILURE);
+	}
+
+	mutex_enter(&plp->pl_mutex);
+	/*
+	 * check if we are transitioning to a legal power level
+	 */
+	if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
+		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh, "pl2303_usb_power: "
+		    "illegal power level %d, pwr_states=%x",
+		    level, pm->pm_pwr_states);
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_FAILURE);
+	}
+
+	/*
+	 * if we are about to raise power and asked to lower power, fail
+	 */
+	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_FAILURE);
+	}
+
+	switch (level) {
+	case USB_DEV_OS_PWR_OFF:
+		rval = pl2303_pwrlvl0(plp);
+
+		break;
+	case USB_DEV_OS_PWR_1:
+		rval = pl2303_pwrlvl1(plp);
+
+		break;
+	case USB_DEV_OS_PWR_2:
+		rval = pl2303_pwrlvl2(plp);
+
+		break;
+	case USB_DEV_OS_FULL_PWR:
+		rval = pl2303_pwrlvl3(plp);
+
+		break;
+	default:
+		ASSERT(0);	/* cannot happen */
+	}
+
+	*new_state = plp->pl_dev_state;
+	mutex_exit(&plp->pl_mutex);
+
+	return (rval);
+}
+
+
+/*
+ * ds_suspend
+ */
+static int
+pl2303_suspend(ds_hdl_t hdl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		state;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_suspend");
+
+	mutex_enter(&plp->pl_mutex);
+	state = plp->pl_dev_state = USB_DEV_SUSPENDED;
+	mutex_exit(&plp->pl_mutex);
+
+	pl2303_disconnect_pipes(plp);
+
+	return (state);
+}
+
+
+/*
+ * ds_resume
+ */
+static int
+pl2303_resume(ds_hdl_t hdl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		current_state;
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_resume");
+
+	(void) pm_busy_component(plp->pl_dip, 0);
+	(void) pm_raise_power(plp->pl_dip, 0, USB_DEV_OS_FULL_PWR);
+
+	mutex_enter(&plp->pl_mutex);
+	current_state = plp->pl_dev_state;
+	mutex_exit(&plp->pl_mutex);
+
+	if (current_state != USB_DEV_ONLINE) {
+		rval = pl2303_restore_device_state(plp);
+	} else {
+		rval = USB_SUCCESS;
+	}
+
+	(void) pm_idle_component(plp->pl_dip, 0);
+
+	return (rval);
+}
+
+
+/*
+ * ds_disconnect
+ */
+static int
+pl2303_disconnect(ds_hdl_t hdl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		state;
+
+	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_disconnect");
+
+	mutex_enter(&plp->pl_mutex);
+	state = plp->pl_dev_state = USB_DEV_DISCONNECTED;
+	mutex_exit(&plp->pl_mutex);
+
+	pl2303_disconnect_pipes(plp);
+
+	return (state);
+}
+
+
+/*
+ * ds_reconnect
+ */
+static int
+pl2303_reconnect(ds_hdl_t hdl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_HOTPLUG, plp->pl_lh, "pl2303_reconnect");
+
+	return (pl2303_restore_device_state(plp));
+}
+
+
+/*
+ * standard UART operations
+ * ------------------------
+ *
+ *
+ * ds_set_port_params
+ */
+/*ARGSUSED*/
+static int
+pl2303_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		rval = USB_FAILURE;
+	mblk_t		*bp;
+	int		i;
+	uint_t		ui;
+	int		baud;
+	int		cnt;
+	ds_port_param_entry_t *pe;
+	uint16_t xonxoff_symbol;
+	uint8_t xon_char;
+	uint8_t xoff_char;
+
+	if (tp == NULL) {
+
+		return (rval);
+	}
+
+	cnt = tp->tp_cnt;
+	pe = tp->tp_entries;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_port_params");
+
+	/*
+	 * get Line Coding Structure Request
+	 * including: baud rate, stop bit, parity type and data bit
+	 */
+	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
+
+		return (rval);
+	}
+
+	/* translate parameters into device-specific bits */
+	for (i = 0; i < cnt; i++, pe++) {
+		switch (pe->param) {
+		case DS_PARAM_BAUD:
+			ui = pe->val.ui;
+
+			/* if we don't support this speed, return USB_FAILURE */
+			if ((ui >= NELEM(pl2303_speedtab)) ||
+			    ((ui > 0) && (pl2303_speedtab[ui] == 0))) {
+				USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh,
+				    "pl2303_set_port_params: bad baud %d", ui);
+
+				return (USB_FAILURE);
+			}
+
+			baud = pl2303_speedtab[ui];
+			bp->b_rptr[0] = baud & 0xff;
+			bp->b_rptr[1] = (baud >> 8) & 0xff;
+			bp->b_rptr[2] = (baud >> 16) & 0xff;
+			bp->b_rptr[3] = (baud >> 24) & 0xff;
+
+			break;
+		case DS_PARAM_PARITY:
+			if (pe->val.ui & PARENB) {
+				if (pe->val.ui & PARODD) {
+					bp->b_rptr[5] = 1;
+				} else {
+					bp->b_rptr[5] = 2;
+				}
+			} else {
+				bp->b_rptr[5] = 0;
+			}
+
+			break;
+		case DS_PARAM_STOPB:
+			if (pe->val.ui & CSTOPB) {
+				bp->b_rptr[4] = 2;
+			} else {
+				bp->b_rptr[4] = 0;
+			}
+
+			break;
+		case DS_PARAM_CHARSZ:
+			switch (pe->val.ui) {
+			case CS5:
+				bp->b_rptr[6] = 5;
+
+				break;
+			case CS6:
+				bp->b_rptr[6] = 6;
+
+				break;
+			case CS7:
+				bp->b_rptr[6] = 7;
+
+				break;
+			case CS8:
+			default:
+				bp->b_rptr[6] = 8;
+
+				break;
+			}
+
+			break;
+		case DS_PARAM_XON_XOFF:
+			/*
+			 * Software flow control: XON/XOFF
+			 * not supported by PL-2303H, HX chips
+			 */
+			if (pe->val.ui & IXON || pe->val.ui & IXOFF) {
+				/* not supported by PL-2303H chip */
+				switch (plp->pl_chiptype) {
+				case pl2303_H:
+
+					break;
+				case pl2303_X:
+					xon_char = pe->val.uc[0];
+					xoff_char = pe->val.uc[1];
+					xonxoff_symbol = (xoff_char << 8)
+							| xon_char;
+
+					rval =  pl2303_cmd_vendor_write0(
+						plp, SET_XONXOFF,
+						xonxoff_symbol);
+
+					if (rval != USB_SUCCESS) {
+						USB_DPRINTF_L3(DPRINT_CTLOP,
+						plp->pl_lh,
+						"pl2303_set_port_params: "
+						"set XonXoff failed");
+					}
+
+					break;
+				case pl2303_UNKNOWN:
+				default:
+
+					break;
+				}
+			}
+
+			break;
+		case DS_PARAM_FLOW_CTL:
+			/* Hardware flow control */
+			if (pe->val.ui & CTSXON) {
+				if ((rval = pl2303_cmd_set_rtscts(plp))
+						!= USB_SUCCESS) {
+
+					USB_DPRINTF_L3(DPRINT_CTLOP,
+						plp->pl_lh,
+						"pl2303_set_port_params: "
+						"pl2303_cmd_set_rtscts failed");
+				}
+			}
+
+			break;
+		default:
+			USB_DPRINTF_L2(DPRINT_CTLOP, plp->pl_lh,
+			    "pl2303_set_port_params: bad param %d", pe->param);
+
+			break;
+		}
+	}
+
+	/* set new values for Line Coding Structure */
+	if ((rval = pl2303_cmd_set_line(plp, bp)) != USB_SUCCESS) {
+
+		return (rval);
+	}
+
+	freeb(bp);
+	bp = NULL;
+
+	/* hardware need to get Line Coding Structure again */
+	if ((rval = pl2303_cmd_get_line(plp, &bp)) != USB_SUCCESS) {
+
+		if (bp != NULL) {
+			freeb(bp);
+		}
+
+		return (rval);
+	}
+
+	if (bp != NULL) {
+		freeb(bp);
+	}
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_set_modem_ctl
+ */
+/*ARGSUSED*/
+static int
+pl2303_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		rval = USB_FAILURE;
+	uint8_t		new_mctl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_set_modem_ctl");
+
+	mutex_enter(&plp->pl_mutex);
+	new_mctl = plp->pl_mctl;
+	mutex_exit(&plp->pl_mutex);
+
+	/* set RTS and DTR */
+	pl2303_mctl2reg(mask, val, &new_mctl);
+
+	if ((rval = pl2303_cmd_set_ctl(plp, new_mctl)) == USB_SUCCESS) {
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_mctl = new_mctl;
+		mutex_exit(&plp->pl_mutex);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * ds_get_modem_ctl
+ */
+/*ARGSUSED*/
+static int
+pl2303_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_get_modem_ctl");
+
+	mutex_enter(&plp->pl_mutex);
+
+	/* get RTS and DTR */
+	*valp = pl2303_reg2mctl(plp->pl_mctl) & mask;
+	*valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI));
+	mutex_exit(&plp->pl_mutex);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_break_ctl
+ */
+/*ARGSUSED*/
+static int
+pl2303_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_break_ctl");
+
+	return (pl2303_cmd_break(plp, ctl));
+}
+
+
+/*
+ * ds_tx
+ */
+/*ARGSUSED*/
+static int
+pl2303_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		xferd;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx");
+
+	/*
+	 * sanity checks
+	 */
+	if (mp == NULL) {
+		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: mp=NULL");
+
+		return (USB_SUCCESS);
+	}
+	if (MBLKL(mp) <= 0) {
+		USB_DPRINTF_L3(DPRINT_CTLOP, plp->pl_lh, "pl2303_tx: len<=0");
+		freemsg(mp);
+
+		return (USB_SUCCESS);
+	}
+
+	mutex_enter(&plp->pl_mutex);
+
+	pl2303_put_tail(&plp->pl_tx_mp, mp);	/* add to the chain */
+
+	pl2303_tx_start(plp, &xferd);
+
+	mutex_exit(&plp->pl_mutex);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_rx
+ * the real data receiving is in pl2303_open_port
+ */
+/*ARGSUSED*/
+static mblk_t *
+pl2303_rx(ds_hdl_t hdl, uint_t port_num)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	mblk_t		*mp;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_rx");
+
+	mutex_enter(&plp->pl_mutex);
+	mp = plp->pl_rx_mp;
+	plp->pl_rx_mp = NULL;
+	mutex_exit(&plp->pl_mutex);
+
+	return (mp);
+}
+
+
+/*
+ * ds_stop
+ */
+/*ARGSUSED*/
+static void
+pl2303_stop(ds_hdl_t hdl, uint_t port_num, int dir)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_stop");
+
+	if (dir & DS_TX) {
+		mutex_enter(&plp->pl_mutex);
+		plp->pl_port_flags |= PL2303_PORT_TX_STOPPED;
+		mutex_exit(&plp->pl_mutex);
+	}
+}
+
+
+/*
+ * ds_start
+ */
+/*ARGSUSED*/
+static void
+pl2303_start(ds_hdl_t hdl, uint_t port_num, int dir)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_start");
+
+	if (dir & DS_TX) {
+		mutex_enter(&plp->pl_mutex);
+		if (plp->pl_port_flags & PL2303_PORT_TX_STOPPED) {
+			plp->pl_port_flags &= ~PL2303_PORT_TX_STOPPED;
+			pl2303_tx_start(plp, NULL);
+		}
+		mutex_exit(&plp->pl_mutex);
+	}
+}
+
+
+/*
+ * ds_fifo_flush
+ */
+/*ARGSUSED*/
+static int
+pl2303_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_flush: dir=%x",
+	    dir);
+
+	mutex_enter(&plp->pl_mutex);
+	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
+
+	if ((dir & DS_TX) && plp->pl_tx_mp) {
+		freemsg(plp->pl_tx_mp);
+		plp->pl_tx_mp = NULL;
+	}
+	if ((dir & DS_RX) && plp->pl_rx_mp) {
+		freemsg(plp->pl_rx_mp);
+		plp->pl_rx_mp = NULL;
+	}
+	mutex_exit(&plp->pl_mutex);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * ds_fifo_drain
+ */
+/*ARGSUSED*/
+static int
+pl2303_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)hdl;
+	int		rval = USB_SUCCESS;
+
+	USB_DPRINTF_L4(DPRINT_CTLOP, plp->pl_lh, "pl2303_fifo_drain");
+
+	mutex_enter(&plp->pl_mutex);
+	ASSERT(plp->pl_port_state == PL2303_PORT_OPEN);
+
+	/*
+	 * for the reason of hardware, set timeout 0
+	 */
+	if (pl2303_wait_tx_drain(plp, 0) != USB_SUCCESS) {
+
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_FAILURE);
+	}
+
+	mutex_exit(&plp->pl_mutex);
+
+	/* wait 500 ms until hw fifo drains */
+	delay(drv_usectohz(500*1000));
+
+	return (rval);
+}
+
+
+/*
+ * configuration routines
+ * ----------------------
+ *
+ * clean up routine
+ */
+static void
+pl2303_cleanup(pl2303_state_t *plp, int level)
+{
+	ASSERT((level > 0) && (level <= PL2303_CLEANUP_LEVEL_MAX));
+
+	switch (level) {
+	default:
+		pl2303_close_pipes(plp);
+		/* FALLTHRU */
+	case 4:
+		usb_unregister_event_cbs(plp->pl_dip, plp->pl_usb_events);
+		/* FALLTHRU */
+	case 3:
+		pl2303_destroy_pm_components(plp);
+		mutex_destroy(&plp->pl_mutex);
+		cv_destroy(&plp->pl_tx_cv);
+		cv_destroy(&plp->pl_rx_cv);
+
+		usb_free_log_hdl(plp->pl_lh);
+		plp->pl_lh = NULL;
+
+		usb_free_descr_tree(plp->pl_dip, plp->pl_dev_data);
+		plp->pl_def_ph = NULL;
+		/* FALLTHRU */
+	case 2:
+		usb_client_detach(plp->pl_dip, plp->pl_dev_data);
+		/* FALLTHRU */
+	case 1:
+		kmem_free(plp, sizeof (pl2303_state_t));
+	}
+}
+
+
+/*
+ * device specific attach
+ */
+static int
+pl2303_dev_attach(pl2303_state_t *plp)
+{
+	if (pl2303_open_pipes(plp) != USB_SUCCESS) {
+		return (USB_FAILURE);
+	}
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * hotplug
+ * -------
+ *
+ *
+ * restore device state after CPR resume or reconnect
+ */
+static int
+pl2303_restore_device_state(pl2303_state_t *plp)
+{
+	int	state;
+
+	mutex_enter(&plp->pl_mutex);
+	state = plp->pl_dev_state;
+	mutex_exit(&plp->pl_mutex);
+
+	if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
+
+		return (state);
+	}
+
+	if (usb_check_same_device(plp->pl_dip, plp->pl_lh, USB_LOG_L2,
+	    DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
+		mutex_enter(&plp->pl_mutex);
+		state = plp->pl_dev_state = USB_DEV_DISCONNECTED;
+		mutex_exit(&plp->pl_mutex);
+
+		return (state);
+	}
+
+	if (state == USB_DEV_DISCONNECTED) {
+		USB_DPRINTF_L0(DPRINT_HOTPLUG, plp->pl_lh,
+		    "Device has been reconnected but data may have been lost");
+	}
+
+	if (pl2303_reconnect_pipes(plp) != USB_SUCCESS) {
+
+		return (state);
+	}
+
+	/*
+	 * init device state
+	 */
+	mutex_enter(&plp->pl_mutex);
+	state = plp->pl_dev_state = USB_DEV_ONLINE;
+	mutex_exit(&plp->pl_mutex);
+
+	if ((pl2303_restore_port_state(plp) != USB_SUCCESS)) {
+		USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
+		    "pl2303_restore_device_state: failed");
+	}
+
+	return (state);
+}
+
+
+/*
+ * restore ports state after CPR resume or reconnect
+ */
+static int
+pl2303_restore_port_state(pl2303_state_t *plp)
+{
+	int		rval;
+
+	mutex_enter(&plp->pl_mutex);
+	if (plp->pl_port_state != PL2303_PORT_OPEN) {
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_SUCCESS);
+	}
+	mutex_exit(&plp->pl_mutex);
+
+	/* open hardware serial port */
+	if ((rval = pl2303_open_hw_port(plp)) != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_HOTPLUG, plp->pl_lh,
+		    "pl2303_restore_ports_state: failed");
+	}
+
+	return (rval);
+}
+
+
+/*
+ * power management
+ * ----------------
+ *
+ *
+ * create PM components
+ */
+static int
+pl2303_create_pm_components(pl2303_state_t *plp)
+{
+	dev_info_t	*dip = plp->pl_dip;
+	pl2303_pm_t	*pm;
+	uint_t		pwr_states;
+
+	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
+		    "pl2303_create_pm_components: failed");
+
+		return (USB_SUCCESS);
+	}
+
+	pm = plp->pl_pm = kmem_zalloc(sizeof (pl2303_pm_t), KM_SLEEP);
+
+	pm->pm_pwr_states = (uint8_t)pwr_states;
+	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
+	pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
+				USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
+
+	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * destroy PM components
+ */
+static void
+pl2303_destroy_pm_components(pl2303_state_t *plp)
+{
+	pl2303_pm_t	*pm = plp->pl_pm;
+	dev_info_t	*dip = plp->pl_dip;
+	int		rval;
+
+	if (!pm)
+
+		return;
+
+	if (plp->pl_dev_state != USB_DEV_DISCONNECTED) {
+		if (pm->pm_wakeup_enabled) {
+			rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+			if (rval != DDI_SUCCESS) {
+				USB_DPRINTF_L1(DPRINT_PM, plp->pl_lh,
+				    "pl2303_destroy_pm_components:"
+				    "raising power failed, rval=%d", rval);
+			}
+
+			rval = usb_handle_remote_wakeup(dip,
+						USB_REMOTE_WAKEUP_DISABLE);
+			if (rval != USB_SUCCESS) {
+				USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
+				    "pl2303_destroy_pm_components: disable "
+				    "remote wakeup failed, rval=%d", rval);
+			}
+		}
+
+		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
+	}
+	kmem_free(pm, sizeof (pl2303_pm_t));
+	plp->pl_pm = NULL;
+}
+
+
+/*
+ * mark device busy and raise power
+ */
+static int
+pl2303_pm_set_busy(pl2303_state_t *plp)
+{
+	pl2303_pm_t	*pm = plp->pl_pm;
+	dev_info_t	*dip = plp->pl_dip;
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_busy");
+
+	if (!pm) {
+
+		return (USB_SUCCESS);
+	}
+
+	mutex_enter(&plp->pl_mutex);
+	/* if already marked busy, just increment the counter */
+	if (pm->pm_busy_cnt++ > 0) {
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_SUCCESS);
+	}
+
+	rval = pm_busy_component(dip, 0);
+	ASSERT(rval == DDI_SUCCESS);
+
+	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
+		mutex_exit(&plp->pl_mutex);
+
+		return (USB_SUCCESS);
+	}
+
+	/* need to raise power  */
+	pm->pm_raise_power = B_TRUE;
+	mutex_exit(&plp->pl_mutex);
+
+	rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+	if (rval != DDI_SUCCESS) {
+		USB_DPRINTF_L1(DPRINT_PM, plp->pl_lh, "raising power failed");
+	}
+
+	mutex_enter(&plp->pl_mutex);
+	pm->pm_raise_power = B_FALSE;
+	mutex_exit(&plp->pl_mutex);
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * mark device idle
+ */
+static void
+pl2303_pm_set_idle(pl2303_state_t *plp)
+{
+	pl2303_pm_t	*pm = plp->pl_pm;
+	dev_info_t	*dip = plp->pl_dip;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pm_set_idle");
+
+	if (!pm) {
+
+		return;
+	}
+
+	/*
+	 * if more ports use the device, do not mark as yet
+	 */
+	mutex_enter(&plp->pl_mutex);
+	if (--pm->pm_busy_cnt > 0) {
+		mutex_exit(&plp->pl_mutex);
+
+		return;
+	}
+
+	if (pm) {
+		(void) pm_idle_component(dip, 0);
+	}
+	mutex_exit(&plp->pl_mutex);
+}
+
+
+/*
+ * Functions to handle power transition for OS levels 0 -> 3
+ * The same level as OS state, different from USB state
+ */
+static int
+pl2303_pwrlvl0(pl2303_state_t *plp)
+{
+	int	rval;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl0");
+
+	switch (plp->pl_dev_state) {
+	case USB_DEV_ONLINE:
+		/* issue USB D3 command to the device */
+		rval = usb_set_device_pwrlvl3(plp->pl_dip);
+		ASSERT(rval == USB_SUCCESS);
+
+		plp->pl_dev_state = USB_DEV_PWRED_DOWN;
+		plp->pl_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
+
+		/* FALLTHRU */
+	case USB_DEV_DISCONNECTED:
+	case USB_DEV_SUSPENDED:
+		/* allow a disconnect/cpr'ed device to go to lower power */
+
+		return (USB_SUCCESS);
+	case USB_DEV_PWRED_DOWN:
+	default:
+		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
+		    "pl2303_pwrlvl0: illegal device state");
+
+		return (USB_FAILURE);
+	}
+}
+
+
+static int
+pl2303_pwrlvl1(pl2303_state_t *plp)
+{
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl1");
+
+	/* issue USB D2 command to the device */
+	(void) usb_set_device_pwrlvl2(plp->pl_dip);
+
+	return (USB_FAILURE);
+}
+
+
+static int
+pl2303_pwrlvl2(pl2303_state_t *plp)
+{
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl2");
+
+	/* issue USB D1 command to the device */
+	(void) usb_set_device_pwrlvl1(plp->pl_dip);
+
+	return (USB_FAILURE);
+}
+
+
+static int
+pl2303_pwrlvl3(pl2303_state_t *plp)
+{
+	int	rval;
+
+	USB_DPRINTF_L4(DPRINT_PM, plp->pl_lh, "pl2303_pwrlvl3");
+
+	switch (plp->pl_dev_state) {
+	case USB_DEV_PWRED_DOWN:
+		/* Issue USB D0 command to the device here */
+		rval = usb_set_device_pwrlvl0(plp->pl_dip);
+		ASSERT(rval == USB_SUCCESS);
+
+		plp->pl_dev_state = USB_DEV_ONLINE;
+		plp->pl_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
+
+		/* FALLTHRU */
+	case USB_DEV_ONLINE:
+		/* we are already in full power */
+
+		/* FALLTHRU */
+	case USB_DEV_DISCONNECTED:
+	case USB_DEV_SUSPENDED:
+
+		return (USB_SUCCESS);
+	default:
+		USB_DPRINTF_L2(DPRINT_PM, plp->pl_lh,
+		    "pl2303_pwrlvl3: illegal device state");
+
+		return (USB_FAILURE);
+	}
+}
+
+
+/*
+ * pipe operations
+ * ---------------
+ *
+ *
+ */
+static int
+pl2303_open_pipes(pl2303_state_t *plp)
+{
+	int		ifc, alt;
+	usb_pipe_policy_t policy;
+	usb_ep_data_t	*in_data, *out_data;
+
+	/* get ep data */
+	ifc = plp->pl_dev_data->dev_curr_if;
+	alt = 0;
+
+	in_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
+	    0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
+
+	out_data = usb_lookup_ep_data(plp->pl_dip, plp->pl_dev_data, ifc, alt,
+	    0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
+
+	if ((in_data == NULL) || (out_data == NULL)) {
+		USB_DPRINTF_L2(DPRINT_ATTACH, plp->pl_lh,
+		    "pl2303_open_pipes: can't get ep data");
+
+		return (USB_FAILURE);
+	}
+
+	/* open pipes */
+	policy.pp_max_async_reqs = 2;
+
+	if (usb_pipe_open(plp->pl_dip, &in_data->ep_descr, &policy,
+	    USB_FLAGS_SLEEP, &plp->pl_bulkin_ph) != USB_SUCCESS) {
+
+		return (USB_FAILURE);
+	}
+
+	if (usb_pipe_open(plp->pl_dip, &out_data->ep_descr, &policy,
+	    USB_FLAGS_SLEEP, &plp->pl_bulkout_ph) != USB_SUCCESS) {
+		usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP,
+		    NULL, NULL);
+
+		return (USB_FAILURE);
+	}
+
+	mutex_enter(&plp->pl_mutex);
+	plp->pl_bulkin_state = PL2303_PIPE_IDLE;
+	plp->pl_bulkout_state = PL2303_PIPE_IDLE;
+	mutex_exit(&plp->pl_mutex);
+
+	return (USB_SUCCESS);
+}
+
+
+static void
+pl2303_close_pipes(pl2303_state_t *plp)
+{
+	mutex_enter(&plp->pl_mutex);
+	if (plp->pl_dev_state == USB_DEV_ONLINE) {
+		USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh,
+		    "pl2303_close_pipes: waiting for idle bulkin\n");
+		while (plp->pl_bulkin_state != PL2303_PIPE_IDLE) {
+			cv_wait(&plp->pl_rx_cv, &plp->pl_mutex);
+		}
+	}
+	mutex_exit(&plp->pl_mutex);
+
+	usb_pipe_close(plp->pl_dip, plp->pl_bulkin_ph, USB_FLAGS_SLEEP, 0, 0);
+	usb_pipe_close(plp->pl_dip, plp->pl_bulkout_ph, USB_FLAGS_SLEEP, 0, 0);
+
+	mutex_enter(&plp->pl_mutex);
+	plp->pl_bulkin_state = PL2303_PIPE_CLOSED;
+	plp->pl_bulkout_state = PL2303_PIPE_CLOSED;
+	mutex_exit(&plp->pl_mutex);
+}
+
+
+static void
+pl2303_disconnect_pipes(pl2303_state_t *plp)
+{
+	pl2303_close_pipes(plp);
+}
+
+
+static int
+pl2303_reconnect_pipes(pl2303_state_t *plp)
+{
+	if ((pl2303_open_pipes(plp) != USB_SUCCESS)) {
+
+		return (USB_FAILURE);
+	}
+
+	return (USB_SUCCESS);
+}
+
+
+/*
+ * pipe callbacks
+ * --------------
+ *
+ *
+ * bulk in common and exeception callback
+ *
+ */
+/*ARGSUSED*/
+void
+pl2303_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
+	mblk_t		*data;
+	int		data_len;
+
+	data = req->bulk_data;
+	data_len = (data) ? MBLKL(data) : 0;
+
+	USB_DPRINTF_L4(DPRINT_IN_PIPE, plp->pl_lh, "pl2303_bulkin_cb: "
+	    "cr=%d len=%d",
+	    req->bulk_completion_reason,
+	    data_len);
+
+	/* save data and notify GSD */
+	if ((plp->pl_port_state == PL2303_PORT_OPEN) && (data_len) &&
+			(req->bulk_completion_reason == USB_CR_OK)) {
+		req->bulk_data = NULL;
+		pl2303_put_tail(&plp->pl_rx_mp, data);
+		if (plp->pl_cb.cb_rx) {
+			plp->pl_cb.cb_rx(plp->pl_cb.cb_arg);
+		}
+	}
+
+	usb_free_bulk_req(req);
+
+	/* receive more */
+	mutex_enter(&plp->pl_mutex);
+	plp->pl_bulkin_state = PL2303_PIPE_IDLE;
+	if (plp->pl_port_state == PL2303_PORT_OPEN) {
+		(void) pl2303_rx_start(plp);
+	} else {
+		plp->pl_bulkin_state = PL2303_PIPE_IDLE;
+		cv_broadcast(&plp->pl_rx_cv);
+	}
+	mutex_exit(&plp->pl_mutex);
+}
+
+
+/*
+ * bulk out common and exeception callback
+ */
+/*ARGSUSED*/
+void
+pl2303_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
+{
+	pl2303_state_t	*plp = (pl2303_state_t *)req->bulk_client_private;
+	int		data_len;
+	mblk_t		*data = req->bulk_data;
+
+	data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
+
+	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
+	    "pl2303_bulkout_cb: cr=%d len=%d",
+	    req->bulk_completion_reason,
+	    data_len);
+
+	if (req->bulk_completion_reason && (data_len > 0)) {
+		pl2303_put_head(&plp->pl_tx_mp, data);
+		req->bulk_data = NULL;
+	}
+
+	usb_free_bulk_req(req);
+
+	/* notify GSD */
+	if (plp->pl_cb.cb_tx) {
+		plp->pl_cb.cb_tx(plp->pl_cb.cb_arg);
+	}
+
+	/* send more */
+	mutex_enter(&plp->pl_mutex);
+	plp->pl_bulkout_state = PL2303_PIPE_IDLE;
+	if (plp->pl_tx_mp == NULL) {
+		cv_broadcast(&plp->pl_tx_cv);
+	} else {
+		pl2303_tx_start(plp, NULL);
+	}
+	mutex_exit(&plp->pl_mutex);
+}
+
+
+/*
+ * data transfer routines
+ * ----------------------
+ *
+ *
+ * start data receipt
+ */
+static int
+pl2303_rx_start(pl2303_state_t *plp)
+{
+	usb_bulk_req_t	*br;
+	int		rval = USB_FAILURE;
+
+	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_rx_start");
+
+	ASSERT(mutex_owned(&plp->pl_mutex));
+
+	plp->pl_bulkin_state = PL2303_PIPE_BUSY;
+	mutex_exit(&plp->pl_mutex);
+
+	br = usb_alloc_bulk_req(plp->pl_dip, plp->pl_xfer_sz, USB_FLAGS_SLEEP);
+	br->bulk_len = plp->pl_xfer_sz;
+	br->bulk_timeout = PL2303_BULKIN_TIMEOUT;
+	br->bulk_cb = pl2303_bulkin_cb;
+	br->bulk_exc_cb = pl2303_bulkin_cb;
+	br->bulk_client_private = (usb_opaque_t)plp;
+	br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
+
+	rval = usb_pipe_bulk_xfer(plp->pl_bulkin_ph, br, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_IN_PIPE, plp->pl_lh,
+		    "pl2303_rx_start: xfer failed %d", rval);
+		usb_free_bulk_req(br);
+	}
+
+	mutex_enter(&plp->pl_mutex);
+	if (rval != USB_SUCCESS) {
+		plp->pl_bulkin_state = PL2303_PIPE_IDLE;
+	}
+
+	return (rval);
+}
+
+
+/*
+ * start data transmit
+ */
+static void
+pl2303_tx_start(pl2303_state_t *plp, int *xferd)
+{
+	int		len;		/* bytes we can transmit */
+	mblk_t		*data;		/* data to be transmitted */
+	int		data_len;	/* bytes in 'data' */
+	mblk_t		*mp;		/* current msgblk */
+	int		copylen;	/* bytes copy from 'mp' to 'data' */
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_tx_start");
+	ASSERT(mutex_owned(&plp->pl_mutex));
+	ASSERT(plp->pl_port_state != PL2303_PORT_CLOSED);
+
+	if (xferd) {
+		*xferd = 0;
+	}
+	if ((plp->pl_port_flags & PL2303_PORT_TX_STOPPED) ||
+	    (plp->pl_tx_mp == NULL)) {
+
+		return;
+	}
+	if (plp->pl_bulkout_state != PL2303_PIPE_IDLE) {
+		USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh,
+		    "pl2303_tx_start: pipe busy");
+
+		return;
+	}
+	ASSERT(MBLKL(plp->pl_tx_mp) > 0);
+
+	/* send as much data as port can receive */
+	len = min(msgdsize(plp->pl_tx_mp), plp->pl_xfer_sz);
+
+	if (len == 0) {
+
+		return;
+	}
+
+	if ((data = allocb(len, BPRI_LO)) == NULL) {
+
+		return;
+	}
+
+	/*
+	 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
+	 */
+	data_len = 0;
+
+	while ((data_len < len) && plp->pl_tx_mp) {
+		mp = plp->pl_tx_mp;
+		copylen = min(MBLKL(mp), len - data_len);
+		bcopy(mp->b_rptr, data->b_wptr, copylen);
+		mp->b_rptr += copylen;
+		data->b_wptr += copylen;
+		data_len += copylen;
+
+		if (MBLKL(mp) <= 0) {
+			plp->pl_tx_mp = unlinkb(mp);
+			freeb(mp);
+		} else {
+			ASSERT(data_len == len);
+		}
+	}
+
+	if (data_len <= 0) {
+		USB_DPRINTF_L3(DPRINT_OUT_PIPE, plp->pl_lh,
+		    "pl2303_tx_start: copied zero bytes");
+		freeb(data);
+
+		return;
+	}
+
+	plp->pl_bulkout_state = PL2303_PIPE_BUSY;
+	mutex_exit(&plp->pl_mutex);
+
+	rval = pl2303_send_data(plp, data);
+	mutex_enter(&plp->pl_mutex);
+
+	if (rval != USB_SUCCESS) {
+		plp->pl_bulkout_state = PL2303_PIPE_IDLE;
+		if (plp->pl_tx_mp == NULL) {
+			plp->pl_tx_mp = data;
+		}
+
+	} else {
+		if (xferd) {
+			*xferd = data_len;
+		}
+	}
+}
+
+
+static int
+pl2303_send_data(pl2303_state_t *plp, mblk_t *data)
+{
+	usb_bulk_req_t	*br;
+	int		len = MBLKL(data);
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_OUT_PIPE, plp->pl_lh, "pl2303_send_data: %d "
+	    "%x %x %x", len, data->b_rptr[0],
+	    (len > 1) ? data->b_rptr[1] : 0,
+	    (len > 2) ? data->b_rptr[2] : 0);
+	ASSERT(!mutex_owned(&plp->pl_mutex));
+
+	br = usb_alloc_bulk_req(plp->pl_dip, 0, USB_FLAGS_SLEEP);
+	br->bulk_data = data;
+	br->bulk_len = len;
+	br->bulk_timeout = PL2303_BULKOUT_TIMEOUT;
+	br->bulk_cb = pl2303_bulkout_cb;
+	br->bulk_exc_cb = pl2303_bulkout_cb;
+	br->bulk_client_private = (usb_opaque_t)plp;
+	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
+
+	rval = usb_pipe_bulk_xfer(plp->pl_bulkout_ph, br, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_OUT_PIPE, plp->pl_lh,
+		    "pl2303_send_data: xfer failed %d", rval);
+		usb_free_bulk_req(br);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * wait until local tx buffer drains.
+ * 'timeout' is in seconds, zero means wait forever
+ */
+static int
+pl2303_wait_tx_drain(pl2303_state_t *plp, int timeout)
+{
+	clock_t	until;
+	int	over = 0;
+
+	until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout);
+
+	while (plp->pl_tx_mp && !over) {
+		if (timeout > 0) {
+			/* whether timedout or signal pending */
+			over = (cv_timedwait_sig(&plp->pl_tx_cv,
+					&plp->pl_mutex, until) <= 0);
+		} else {
+			/* whether a signal is pending */
+			over = (cv_wait_sig(&plp->pl_tx_cv,
+					&plp->pl_mutex) == 0);
+		}
+	}
+
+	return ((plp->pl_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
+}
+
+
+/*
+ * device operations
+ * -----------------
+ *
+ *
+ * initialize hardware serial port
+ */
+static int
+pl2303_open_hw_port(pl2303_state_t *plp)
+{
+	int		rval = USB_SUCCESS;
+
+	/*
+	 * initialize three Device Configuration Registers (DCR):
+	 * DCR0, DCR1, and DCR2
+	 */
+
+	switch (plp->pl_chiptype) {
+	case (pl2303_H):
+		/* Set DCR0 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
+					DCR0_INIT_H)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* Set DCR1 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
+					DCR1_INIT_H)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* Set DCR2 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
+					DCR2_INIT_H)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		break;
+	case (pl2303_X):
+
+		/* Set DCR0 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR0,
+					DCR0_INIT)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* Set DCR1 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR1,
+					DCR1_INIT_X)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* Set DCR2 */
+		if ((rval = pl2303_cmd_vendor_write0(plp, SET_DCR2,
+					DCR2_INIT_X)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* reset Downstream data pipes */
+		if ((rval = pl2303_cmd_vendor_write0(plp,
+			RESET_DOWNSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		/* reset Upstream data pipes */
+		if ((rval = pl2303_cmd_vendor_write0(plp,
+				RESET_UPSTREAM_DATA_PIPE, 0)) != USB_SUCCESS) {
+
+			return (rval);
+		}
+
+		break;
+	case (pl2303_UNKNOWN):
+	default:
+		USB_DPRINTF_L2(DPRINT_OPEN, plp->pl_lh,
+			"pl2303_open_hw_port: unknown chiptype");
+
+		rval = USB_FAILURE;
+	}
+
+	return (rval);
+}
+
+
+/*
+ * vendor-specific commands
+ * ------------------------
+ *
+ *
+ * Get_Line_Coding Request
+ */
+static int
+pl2303_cmd_get_line(pl2303_state_t *plp, mblk_t **data)
+{
+	usb_ctrl_setup_t setup = { PL2303_GET_LINE_CODING_REQUEST_TYPE,
+			PL2303_GET_LINE_CODING_REQUEST, 0, 0,
+			PL2303_GET_LINE_CODING_LENGTH, 0 };
+	usb_cb_flags_t	cb_flags;
+	usb_cr_t	cr;
+	int		rval;
+
+	*data = NULL;
+
+	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, data,
+		&cr, &cb_flags, 0);
+
+	if ((rval == USB_SUCCESS) && (*data != NULL)) {
+		USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
+		    "pl2303_cmd_get_line: %x %x %x %x %x %x %x",
+		    (*data)->b_rptr[0], (*data)->b_rptr[1], (*data)->b_rptr[2],
+		    (*data)->b_rptr[3], (*data)->b_rptr[4], (*data)->b_rptr[5],
+		    (*data)->b_rptr[6]);
+	} else {
+		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
+		    "pl2303_cmd_get_line: failed %d %d %x",
+		    rval, cr, cb_flags);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * Set_Line_Coding Request
+ */
+static int
+pl2303_cmd_set_line(pl2303_state_t *plp, mblk_t *data)
+{
+	usb_ctrl_setup_t setup = { PL2303_SET_LINE_CODING_REQUEST_TYPE,
+			PL2303_SET_LINE_CODING_REQUEST, 0, 0,
+			PL2303_SET_LINE_CODING_LENGTH, 0 };
+	usb_cb_flags_t	cb_flags;
+	usb_cr_t	cr;
+	int		rval;
+
+	USB_DPRINTF_L4(DPRINT_DEF_PIPE, plp->pl_lh,
+	    "pl2303_cmd_set_line: %x %x %x %x %x %x %x",
+	    data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
+	    data->b_rptr[3], data->b_rptr[4], data->b_rptr[5], data->b_rptr[6]);
+
+	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, &data,
+		&cr, &cb_flags, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
+		    "pl2303_cmd_set_line: failed %d %d %x",
+		    rval, cr, cb_flags);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * Set_Control_Line_State Request to RTS and DTR
+ */
+static int
+pl2303_cmd_set_ctl(pl2303_state_t *plp, uint8_t val)
+{
+	usb_ctrl_setup_t setup = { PL2303_SET_CONTROL_REQUEST_TYPE,
+			PL2303_SET_CONTROL_REQUEST, 0, 0,
+			PL2303_SET_CONTROL_LENGTH, 0 };
+	usb_cb_flags_t	cb_flags;
+	usb_cr_t	cr;
+	int		rval;
+
+	setup.wValue = val;
+
+	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
+		&cr, &cb_flags, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
+		    "pl2303_cmd_set_ctl: failed %d %d %x",
+		    rval, cr, cb_flags);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * Vendor_Specific_Write Request
+ * wLength: 0
+ */
+static int
+pl2303_cmd_vendor_write0(pl2303_state_t *plp, uint16_t value, int16_t index)
+{
+	usb_ctrl_setup_t setup = { PL2303_VENDOR_WRITE_REQUEST_TYPE,
+			PL2303_VENDOR_WRITE_REQUEST, 0, 0,
+			PL2303_VENDOR_WRITE_LENGTH, 0 };
+	usb_cb_flags_t	cb_flags;
+	usb_cr_t	cr;
+	int		rval;
+
+	setup.wValue = value;
+	setup.wIndex = index;
+
+	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
+		&cr, &cb_flags, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
+		    "pl2303_cmd_vendor_write0: %x %x failed %d %d %x",
+		    value, index, rval, cr, cb_flags);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * For Hardware flow control
+ */
+static int
+pl2303_cmd_set_rtscts(pl2303_state_t *plp)
+{
+	/* Set DCR0 */
+	switch (plp->pl_chiptype) {
+	case pl2303_H:
+
+		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_H));
+	case pl2303_X:
+
+		return (pl2303_cmd_vendor_write0(plp, SET_DCR0, DCR0_INIT_X));
+	case pl2303_UNKNOWN:
+	default:
+
+		return (USB_FAILURE);
+	}
+}
+
+
+/*
+ * Set TxD BREAK_ON or BREAK_OFF
+ */
+static int
+pl2303_cmd_break(pl2303_state_t *plp, int ctl)
+{
+	usb_ctrl_setup_t setup = { PL2303_BREAK_REQUEST_TYPE,
+			PL2303_BREAK_REQUEST, 0, 0,
+			PL2303_BREAK_LENGTH, 0 };
+	usb_cb_flags_t	cb_flags;
+	usb_cr_t	cr;
+	int		rval;
+
+	setup.wValue = (ctl == DS_ON) ? PL2303_BREAK_ON : PL2303_BREAK_OFF;
+
+	rval = usb_pipe_ctrl_xfer_wait(plp->pl_def_ph, &setup, NULL,
+		&cr, &cb_flags, 0);
+
+	if (rval != USB_SUCCESS) {
+		USB_DPRINTF_L2(DPRINT_DEF_PIPE, plp->pl_lh,
+			"pl2303_cmd_break: failed rval=%d,cr=%d,cb_flags=0x%x",
+			rval, cr, cb_flags);
+	}
+
+	return (rval);
+}
+
+
+/*
+ * for set_mod_ctl
+ */
+static void
+pl2303_mctl2reg(int mask, int val, uint8_t *line_ctl)
+{
+	if (mask & TIOCM_RTS) {
+		if (val & TIOCM_RTS) {
+			*line_ctl |= PL2303_CONTROL_RTS;
+		} else {
+			*line_ctl &= ~PL2303_CONTROL_RTS;
+		}
+	}
+	if (mask & TIOCM_DTR) {
+		if (val & TIOCM_DTR) {
+			*line_ctl |= PL2303_CONTROL_DTR;
+		} else {
+			*line_ctl &= ~PL2303_CONTROL_DTR;
+		}
+	}
+}
+
+
+/*
+ * for get_mod_ctl
+ */
+static int
+pl2303_reg2mctl(uint8_t line_ctl)
+{
+	int	val = 0;
+
+	if (line_ctl & PL2303_CONTROL_RTS) {
+		val |= TIOCM_RTS;
+	}
+	if (line_ctl & PL2303_CONTROL_DTR) {
+		val |= TIOCM_DTR;
+	}
+
+	return (val);
+}
+
+
+/*
+ * misc routines
+ * -------------
+ *
+ */
+
+/*
+ * link a message block to tail of message
+ * account for the case when message is null
+ */
+static void
+pl2303_put_tail(mblk_t **mpp, mblk_t *bp)
+{
+	if (*mpp) {
+		linkb(*mpp, bp);
+	} else {
+		*mpp = bp;
+	}
+}
+
+
+/*
+ * put a message block at the head of the message
+ * account for the case when message is null
+ */
+static void
+pl2303_put_head(mblk_t **mpp, mblk_t *bp)
+{
+	if (*mpp) {
+		linkb(bp, *mpp);
+	}
+	*mpp = bp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/usb/clients/usbser/usbsprl/usbser_pl2303.c	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,225 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * This driver supports Prolific PL-2303H/HX/X USB-to-serial adapters. It is a
+ * device-specific driver (DSD) working with USB generic serial driver (GSD). It
+ * implements the USB-to-serial device-specific driver interface (DSDI) which is
+ * offered by GSD. The interface is defined by ds_ops_t structure.
+ *
+ *
+ * PL-2303HX and PL-2303X devices have different hardware, but from the
+ * perspective of device driver, they have the same software interface.
+ */
+
+/*
+ *
+ * USB Prolific PL2303 driver glue code
+ *
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stream.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#include <sys/usb/clients/usbser/usbser.h>
+#include <sys/usb/clients/usbser/usbsprl/pl2303_var.h>
+
+
+/* configuration entry points */
+static int	usbser_pl2303_attach(dev_info_t *, ddi_attach_cmd_t);
+static int	usbser_pl2303_detach(dev_info_t *, ddi_detach_cmd_t);
+static int 	usbser_pl2303_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
+		void **);
+static int	usbser_pl2303_open(queue_t *, dev_t *, int, int, cred_t *);
+static void	*usbser_pl2303_statep;	/* soft state */
+
+extern		ds_ops_t ds_ops;	/* DSD operations */
+
+
+/*
+ * STREAMS structures
+ */
+struct module_info usbser_pl2303_modinfo = {
+	0,			/* module id */
+	"usbsprl",		/* module name */
+	USBSER_MIN_PKTSZ,	/* min pkt size */
+	USBSER_MAX_PKTSZ,	/* max pkt size */
+	USBSER_HIWAT,		/* hi watermark */
+	USBSER_LOWAT		/* low watermark */
+};
+
+
+static struct qinit usbser_pl2303_rinit = {
+	putq,
+	usbser_rsrv,
+	usbser_pl2303_open,
+	usbser_close,
+	NULL,
+	&usbser_pl2303_modinfo,
+	NULL
+};
+
+
+static struct qinit usbser_pl2303_winit = {
+	usbser_wput,
+	usbser_wsrv,
+	NULL,
+	NULL,
+	NULL,
+	&usbser_pl2303_modinfo,
+	NULL
+};
+
+
+struct streamtab usbser_pl2303_str_info = {
+	&usbser_pl2303_rinit, &usbser_pl2303_winit, NULL, NULL
+};
+
+
+static struct cb_ops usbser_pl2303_cb_ops = {
+	nodev,			/* cb_open */
+	nodev,			/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	nodev,			/* cb_read */
+	nodev,			/* cb_write */
+	nodev,			/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	&usbser_pl2303_str_info,			/* cb_stream */
+	(int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG)	/* cb_flag */
+};
+
+
+/*
+ * auto configuration ops
+ */
+struct dev_ops usbser_pl2303_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	usbser_pl2303_getinfo,	/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	nulldev,		/* devo_probe */
+	usbser_pl2303_attach,	/* devo_attach */
+	usbser_pl2303_detach,	/* devo_detach */
+	nodev,			/* devo_reset */
+	&usbser_pl2303_cb_ops,	/* devo_cb_ops */
+	(struct bus_ops *)NULL,	/* devo_bus_ops */
+	usbser_power		/* devo_power */
+};
+
+
+extern struct mod_ops mod_driverops;
+
+
+static struct modldrv modldrv = {
+	&mod_driverops,		/* type of module - driver */
+	"USB Prolific PL2303 driver 1.1",
+	&usbser_pl2303_ops,
+};
+
+
+static struct modlinkage modlinkage = {
+	MODREV_1, &modldrv, 0
+};
+
+
+/*
+ * entry points
+ * ------------
+ *
+ */
+int
+_init(void)
+{
+	int    error;
+
+	if ((error = mod_install(&modlinkage)) == 0) {
+		error = ddi_soft_state_init(&usbser_pl2303_statep,
+				usbser_soft_state_size(), 1);
+	}
+
+	return (error);
+}
+
+
+int
+_fini(void)
+{
+	int    error;
+
+	if ((error = mod_remove(&modlinkage)) == 0) {
+		ddi_soft_state_fini(&usbser_pl2303_statep);
+	}
+
+	return (error);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+int
+usbser_pl2303_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
+		void **result)
+{
+	return (usbser_getinfo(dip, infocmd, arg, result,
+	    usbser_pl2303_statep));
+}
+
+
+static int
+usbser_pl2303_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	return (usbser_attach(dip, cmd, usbser_pl2303_statep, &ds_ops));
+}
+
+
+static int
+usbser_pl2303_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	return (usbser_detach(dip, cmd, usbser_pl2303_statep));
+}
+
+
+static int
+usbser_pl2303_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
+{
+	return (usbser_open(rq, dev, flag, sflag, cr, usbser_pl2303_statep));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/usb/clients/usbser/usbsprl/pl2303_var.h	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,180 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_USB_USBSER_PL2303_VAR_H
+#define	_SYS_USB_USBSER_PL2303_VAR_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * USB PL2303 definitions
+ */
+
+#include <sys/types.h>
+#include <sys/dditypes.h>
+#include <sys/note.h>
+
+#include <sys/usb/clients/usbser/usbser_dsdi.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * PM support
+ */
+typedef struct pl2303_power {
+	uint8_t		pm_wakeup_enabled;	/* remote wakeup enabled */
+	uint8_t		pm_pwr_states;	/* bit mask of power states */
+	boolean_t	pm_raise_power;	/* driver is about to raise power */
+	uint8_t		pm_cur_power;	/* current power level */
+	uint_t		pm_busy_cnt;	/* number of set_busy requests */
+} pl2303_pm_t;
+
+
+/*
+ * From device driver's perspective, there is no difference
+ * between PL-2303HX and PL-2303X chips, so pl2303_X will
+ * stand for two chiptypes
+ */
+enum pl2303_chip {
+	pl2303_H,		/* PL-2303H chip */
+	pl2303_X,		/* PL-2303HX and PL-2303X chip */
+	pl2303_UNKNOWN		/* Unkown chip type */
+};
+
+/*
+ * per device state structure
+ */
+typedef struct pl2303_state {
+	kmutex_t		pl_mutex;		/* structure lock */
+	dev_info_t		*pl_dip;		/* device info */
+	int			pl_dev_flags;		/* device flags */
+	int			pl_port_state;		/* port state */
+	int			pl_port_flags;		/* port flags */
+	ds_cb_t			pl_cb;			/* DSD callbacks */
+	/*
+	 * USBA
+	 */
+	usb_client_dev_data_t	*pl_dev_data;		/* registration data */
+	usb_event_t		*pl_usb_events;		/* usb events */
+	usb_pipe_handle_t	pl_def_ph;		/* default pipe hdl */
+	usb_pipe_handle_t	pl_bulkin_ph;		/* in pipe hdl */
+	int			pl_bulkin_state;	/* in pipe state */
+	usb_pipe_handle_t	pl_bulkout_ph;		/* in pipe hdl */
+	int			pl_bulkout_state;	/* out pipe state */
+	usb_log_handle_t	pl_lh;			/* USBA log handle */
+	int			pl_dev_state;		/* USB device state */
+	size_t			pl_xfer_sz;		/* HCI bulk xfer size */
+	pl2303_pm_t		*pl_pm;			/* PM support */
+	/*
+	 * data receipt and transmit
+	 */
+	mblk_t			*pl_rx_mp;		/* rx data */
+	mblk_t			*pl_tx_mp;		/* tx data */
+	kcondvar_t		pl_tx_cv;		/* tx completion */
+	kcondvar_t		pl_rx_cv;		/* rx completion */
+	/*
+	 * other
+	 */
+	uint8_t			pl_mctl;		/* modem controls */
+	enum pl2303_chip	pl_chiptype;		/* chip type */
+} pl2303_state_t;
+
+_NOTE(MUTEX_PROTECTS_DATA(pl2303_state::pl_mutex, pl2303_state))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(pl2303_state::{
+	pl_dip
+	pl_dev_data
+	pl_usb_events
+	pl_def_ph
+	pl_lh
+	pl_xfer_sz
+	pl_pm
+	pl_port_state
+	pl_cb.cb_rx
+	pl_cb.cb_tx
+	pl_cb.cb_arg
+	pl_bulkin_ph
+	pl_bulkout_ph
+	pl_chiptype
+}))
+
+
+/* port state */
+enum {
+	PL2303_PORT_CLOSED,			/* port is closed */
+	PL2303_PORT_OPEN,			/* port is open */
+	PL2303_PORT_CLOSING
+};
+
+/* port flags */
+enum {
+	PL2303_PORT_TX_STOPPED	= 0x0001	/* transmit not allowed */
+};
+
+/* pipe state */
+enum {
+	PL2303_PIPE_CLOSED,			/* pipe is closed */
+	PL2303_PIPE_IDLE,			/* open but no requests */
+	PL2303_PIPE_BUSY			/* servicing request */
+};
+
+/* various tunables */
+enum {
+	PL2303_BULKOUT_TIMEOUT		= 15,	/* bulkout timeout */
+	PL2303_BULKIN_TIMEOUT		= 15,	/* bulkin timeout */
+	PL2303_XFER_SZ_MAX		= 64,	/* max xfer size */
+	PL2303_CLEANUP_LEVEL_MAX	= 5	/* cleanup level */
+};
+
+
+/*
+ * debug printing masks
+ */
+#define	DPRINT_ATTACH		0x00000001
+#define	DPRINT_OPEN		0x00000002
+#define	DPRINT_CLOSE		0x00000004
+#define	DPRINT_DEF_PIPE		0x00000010
+#define	DPRINT_IN_PIPE		0x00000020
+#define	DPRINT_OUT_PIPE		0x00000040
+#define	DPRINT_IN_DATA		0x00000400
+#define	DPRINT_OUT_DATA		0x00000800
+#define	DPRINT_CTLOP		0x00001000
+#define	DPRINT_HOTPLUG		0x00002000
+#define	DPRINT_PM		0x00004000
+#define	DPRINT_MASK_ALL		0xFFFFFFFF
+
+
+/*
+ * misc macros
+ */
+#define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_USB_USBSER_PL2303_VAR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/usb/clients/usbser/usbsprl/pl2303_vendor.h	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_USB_USBSER_PL2303_VENDOR_H
+#define	_SYS_USB_USBSER_PL2303_VENDOR_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Prolific PL2303 vendor-specific variables
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Prolific PL2303 Vendor and Product IDs
+ */
+
+#define	PROLIFIC_REV_H				0x0202
+#define	PROLIFIC_REV_X				0x0300
+
+/*
+ * Vendor-specific Requests
+ */
+#define	PL2303_SET_LINE_CODING_REQUEST_TYPE	0x21
+#define	PL2303_SET_LINE_CODING_REQUEST		0x20
+#define	PL2303_SET_LINE_CODING_LENGTH		0x07
+
+#define	PL2303_GET_LINE_CODING_REQUEST_TYPE	0xa1
+#define	PL2303_GET_LINE_CODING_REQUEST		0x21
+#define	PL2303_GET_LINE_CODING_LENGTH		0x07
+
+#define	PL2303_SET_CONTROL_REQUEST_TYPE		0x21
+#define	PL2303_SET_CONTROL_REQUEST		0x22
+#define	PL2303_SET_CONTROL_LENGTH		0x00
+#define	PL2303_CONTROL_DTR			0x01
+#define	PL2303_CONTROL_RTS			0x02
+
+#define	PL2303_BREAK_REQUEST_TYPE		0x21
+#define	PL2303_BREAK_REQUEST			0x23
+#define	PL2303_BREAK_LENGTH			0X00
+#define	PL2303_BREAK_ON				0xffff
+#define	PL2303_BREAK_OFF			0x0000
+
+#define	PL2303_VENDOR_WRITE_REQUEST_TYPE	0x40
+#define	PL2303_VENDOR_WRITE_REQUEST		0x01
+#define	PL2303_VENDOR_WRITE_LENGTH		0x00
+
+#define	PL2303_VENDOR_READ_REQUEST_TYPE		0xc0
+#define	PL2303_VENDOR_READ_REQUEST		0x01
+#define	PL2303_VENDOR_READ_LENGTH		0x01
+
+/*
+ * Cmds of setting XON/XOFF symbol
+ */
+#define	SET_XONXOFF				0x05
+
+/*
+ * Device Configuration Registers (DCR0, DCR1, DCR2)
+ */
+#define	SET_DCR0				0x00
+#define	GET_DCR0				0x80
+#define	DCR0_INIT				0x01
+#define	DCR0_INIT_H				0x41
+#define	DCR0_INIT_X				0x61
+
+#define	SET_DCR1				0x01
+#define	GET_DCR1				0x81
+#define	DCR1_INIT_H				0x80
+#define	DCR1_INIT_X				0x00
+
+#define	SET_DCR2				0x02
+#define	GET_DCR2				0x82
+#define	DCR2_INIT_H				0x24
+#define	DCR2_INIT_X				0x44
+
+/*
+ * On-chip Date Buffers:
+ */
+#define	RESET_DOWNSTREAM_DATA_PIPE		0x08
+#define	RESET_UPSTREAM_DATA_PIPE		0x09
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_USB_USBSER_PL2303_VENDOR_H */
--- a/usr/src/uts/intel/Makefile.intel	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/uts/intel/Makefile.intel	Mon Nov 14 02:38:25 2005 -0800
@@ -360,6 +360,7 @@
 DRV_KMODS	+= usbser
 DRV_KMODS	+= usbser_edge
 DRV_KMODS	+= usbsksp
+DRV_KMODS	+= usbsprl
 DRV_KMODS	+= usb_ac
 DRV_KMODS	+= usb_as
 DRV_KMODS	+= usbskel
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/usbsprl/Makefile	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,79 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/intel/usbsprl/Makefile
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma	ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the PL2303 USB Serial
+#	Adapter driver.
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= usbsprl
+OBJECTS		= $(USBSPRL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(USBSPRL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+LDFLAGS         += -dy -Nmisc/usba -Nmisc/usbser
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+def:		$(DEF_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/uts/sparc/Makefile.sparc	Mon Nov 14 02:38:25 2005 -0800
@@ -249,7 +249,7 @@
 DRV_KMODS	+= ecpp
 DRV_KMODS	+= uata dad ifp
 DRV_KMODS	+= hid hubd ehci ohci uhci usb_mid scsa2usb usbprn ugen
-DRV_KMODS	+= usbser usbser_edge usbsksp
+DRV_KMODS	+= usbser usbser_edge usbsksp usbsprl
 DRV_KMODS	+= usb_as usb_ac
 DRV_KMODS	+= usbskel
 DRV_KMODS	+= hci1394 av1394 scsa1394 dcam1394
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/usbsprl/Makefile	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,149 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sparc/usbsprl/Makefile
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma	ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the Prolific USB Serial
+#	Adapter driver.
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= usbsprl
+OBJECTS		= $(USBSPRL_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(USBSPRL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+WARLOCK_OK	= $(MODULE).ok
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+# 
+# lint pass one enforcement 
+# 
+CFLAGS += $(CCVERBOSE)
+
+LDFLAGS         += -dy -Nmisc/usba -Nmisc/usbser
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+def:		$(DEF_DEPS)
+
+clean:		$(CLEAN_DEPS); \
+                $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+clobber:	$(CLOBBER_DEPS); \
+                $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
+
+#
+#	Defines for local commands.
+#
+WLCC		= wlcc
+TOUCH		= touch
+WARLOCK		= warlock
+SCCS		= sccs
+TEST		= test
+
+#
+#	warlock
+#
+WARLOCK_OUT	= usbser_pl2303.ll pl2303_dsd.ll
+WARLOCK_CMD	= $(MODULE).wlcmd
+
+USBSER_FILES = $(USBSER_OBJS:%.o=../usbser/%.ll)
+USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll)
+UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll)
+OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll)
+EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll)
+
+warlock: $(WARLOCK_OK) warlock_with_usba
+
+%.wlcmd:
+	$(TEST) -f $@ || $(SCCS) get $@
+
+$(WARLOCK_OK): warlock_with_usbser
+	$(TOUCH) $@
+
+%.ll: $(UTSBASE)/common/io/usb/clients/usbser/usbsprl/%.c
+	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_with_usbser: $(WARLOCK_OUT) usbser_files warlock_ddi.files
+	$(WARLOCK) -c $(WARLOCK_CMD) $(WARLOCK_OUT) \
+		$(USBSER_FILES) -l ../warlock/ddi_dki_impl.ll
+
+usbser_files:
+	@cd ../usbser; pwd; $(MAKE) usbser.ll
+
+warlock_with_usba: $(WARLOCK_CMD) $(WARLOCK_OUT) usbser_files \
+	usba_files ohci_files uhci_files ehci_files warlock_ddi.files
+	$(WARLOCK) -c usbsprl_with_usba.wlcmd \
+		$(USBA_FILES) $(OHCI_FILES) $(EHCI_FILES) $(UHCI_FILES) \
+		$(USBSER_FILES) \
+		$(WARLOCK_OUT) -l ../warlock/ddi_dki_impl.ll
+
+usba_files:
+	@cd ../usba;pwd; $(MAKE) warlock
+
+uhci_files:
+	@cd ../uhci;pwd; $(MAKE) warlock
+
+ohci_files:
+	@cd ../ohci;pwd; $(MAKE) warlock
+
+ehci_files:
+	@cd ../ehci;pwd; $(MAKE) warlock
+
+warlock_ddi.files:
+	cd ../warlock; pwd; $(MAKE) warlock
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/usbsprl/usbsprl.wlcmd	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,83 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+one usbser_state
+one pl2303_state
+
+### specify the root functions
+
+root usbser_soft_state_size
+root usbser_pl2303_open
+root usbser_close
+root usbser_wput
+root usbser_wsrv
+root usbser_rsrv
+root usbser_tx_cb
+root usbser_rx_cb
+root usbser_status_cb
+root usbser_wq_thread
+root usbser_rq_thread
+root usbser_disconnect_cb
+root usbser_reconnect_cb
+root usbser_cpr_suspend
+root usbser_cpr_resume
+
+root pl2303_bulkin_cb
+root pl2303_bulkout_cb
+
+### specify pl2303 function pointers
+
+add ds_ops::ds_attach targets pl2303_attach
+add ds_ops::ds_detach targets pl2303_detach
+add ds_ops::ds_register_cb targets pl2303_register_cb
+add ds_ops::ds_unregister_cb targets pl2303_unregister_cb
+add ds_ops::ds_open_port targets pl2303_open_port
+add ds_ops::ds_close_port targets pl2303_close_port
+add ds_ops::ds_usb_power targets pl2303_usb_power
+add ds_ops::ds_suspend targets pl2303_suspend
+add ds_ops::ds_resume targets pl2303_resume
+add ds_ops::ds_disconnect targets pl2303_disconnect
+add ds_ops::ds_reconnect targets pl2303_reconnect
+add ds_ops::ds_set_port_params targets pl2303_set_port_params
+add ds_ops::ds_set_modem_ctl targets pl2303_set_modem_ctl
+add ds_ops::ds_get_modem_ctl targets pl2303_get_modem_ctl
+add ds_ops::ds_break_ctl targets pl2303_break_ctl
+add ds_ops::ds_tx targets pl2303_tx
+add ds_ops::ds_rx targets pl2303_rx
+add ds_ops::ds_stop targets pl2303_stop
+add ds_ops::ds_start targets pl2303_start
+add ds_ops::ds_fifo_flush targets pl2303_fifo_flush
+add ds_ops::ds_fifo_drain targets pl2303_fifo_drain
+
+add pl2303_state::pl_cb.cb_tx targets usbser_tx_cb
+add pl2303_state::pl_cb.cb_rx targets usbser_rx_cb
+
+add bus_ops::bus_add_eventcall targets warlock_dummy
+add bus_ops::bus_get_eventcookie targets warlock_dummy
+add bus_ops::bus_post_event targets warlock_dummy
+add bus_ops::bus_remove_eventcall targets warlock_dummy
+add bus_ops::bus_intr_ctl targets warlock_dummy
+add bus_ops::bus_config targets warlock_dummy
+add bus_ops::bus_unconfig targets warlock_dummy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/usbsprl/usbsprl_with_usba.wlcmd	Mon Nov 14 02:38:25 2005 -0800
@@ -0,0 +1,204 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+one ohci_state
+one ehci_state
+one uhci_state
+one usbser_state
+one pl2303_state
+
+### specify the root functions
+
+root usb_console_input_enter
+root usb_console_input_exit
+root usb_console_input_fini
+root usb_console_input_init
+root usb_console_read
+root usb_get_dev_descr
+root usb_get_if_number
+root usb_parse_CV_cfg_descr
+root usb_parse_CV_ep_descr
+root usb_parse_CV_if_descr
+root usb_pipe_get_private
+root usb_get_current_frame_number
+root usb_get_max_isoc_pkts
+root usb_pipe_set_private
+root usba_ready_interface_node
+root usba_free_hcdi_ops
+root usba_async_req_raise_power
+root usba_async_req_lower_power
+root usb_req_raise_power
+root usb_req_lower_power
+root usb_set_device_pwrlvl0
+root usb_set_device_pwrlvl1
+root usb_set_device_pwrlvl2
+root usb_set_device_pwrlvl3
+root usb_is_pm_enabled
+root usb_async_req
+root usb_pipe_bulk_transfer_size
+root usb_get_ep_data
+root usba_pipe_get_policy
+root usb_pipe_ctrl_xfer_wait
+root usb_pipe_drain_reqs
+root usb_try_serialize_access
+root usb_fini_serialization
+root usb_init_serialization
+root usb_release_access
+root usb_serialize_access
+root usb_clr_feature
+root usb_clear_feature
+root usb_get_alt_if
+root usb_get_ep_descr
+root usb_get_if_descr
+root usb_log
+root usb_pipe_isoc_xfer
+root usb_pipe_stop_isoc_polling
+root usb_set_alt_if
+root usb_set_cfg
+root usb_get_cfg
+root usb_ep_num
+root usb_get_status
+root usb_pipe_reset
+root usb_log_descr_tree
+root usb_print_descr_tree
+root usb_rval2errno
+root usb_register_hotplug_cbs
+root usb_get_current_cfgidx
+root usb_register_client
+
+root usb_ugen_attach
+root usb_ugen_close
+root usb_ugen_detach
+root usb_ugen_disconnect_ev_cb
+root usb_ugen_get_hdl
+root usb_ugen_open
+root usb_ugen_poll
+root usb_ugen_power
+root usb_ugen_read
+root usb_ugen_reconnect_ev_cb
+root usb_ugen_write
+
+root hcdi_autoclearing
+root hcdi_cb_thread
+root hcdi_shared_cb_thread
+
+root hubd_restore_state_cb
+root hubd_disconnect_event_cb
+root hubd_post_resume_event_cb
+root hubd_pre_suspend_event_cb
+root hubd_reconnect_event_cb
+root hubd_hotplug_thread
+root hubd_cpr_post_user_callb
+root hubd_root_hub_cleanup_thread
+root hubd_bus_power
+
+root usba_pipe_do_async_func_thread
+root usba_pipe_sync_reset
+root usba_get_hc_dma_attr
+root usba_hcdi_get_req_private
+root usba_hcdi_set_req_private
+root usba_dbuf_tail
+root usba_hubdi_power
+root usba_hubdi_root_hub_power
+root usba_get_hotplug_stats
+root usba_reset_hotplug_stats
+root usba_ascii_string_descr
+root usba_move_list
+root usba_taskq_destroy
+root usba_mk_mctl
+root usb_fail_checkpoint
+
+root ohci_intr
+root ehci_intr
+
+### specify the pl2303 root functions
+
+root usbser_soft_state_size
+root usbser_pl2303_open
+root usbser_close
+root usbser_wput
+root usbser_wsrv
+root usbser_rsrv
+root usbser_tx_cb
+root usbser_rx_cb
+root usbser_status_cb
+root usbser_wq_thread
+root usbser_rq_thread
+root usbser_disconnect_cb
+root usbser_reconnect_cb
+root usbser_cpr_suspend
+root usbser_cpr_resume
+
+root pl2303_bulkin_cb
+root pl2303_bulkout_cb
+
+### specify pl2303 function pointers
+
+add ds_ops::ds_attach targets pl2303_attach
+add ds_ops::ds_detach targets pl2303_detach
+add ds_ops::ds_register_cb targets pl2303_register_cb
+add ds_ops::ds_unregister_cb targets pl2303_unregister_cb
+add ds_ops::ds_open_port targets pl2303_open_port
+add ds_ops::ds_close_port targets pl2303_close_port
+add ds_ops::ds_usb_power targets pl2303_usb_power
+add ds_ops::ds_suspend targets pl2303_suspend
+add ds_ops::ds_resume targets pl2303_resume
+add ds_ops::ds_disconnect targets pl2303_disconnect
+add ds_ops::ds_reconnect targets pl2303_reconnect
+add ds_ops::ds_set_port_params targets pl2303_set_port_params
+add ds_ops::ds_set_modem_ctl targets pl2303_set_modem_ctl
+add ds_ops::ds_get_modem_ctl targets pl2303_get_modem_ctl
+add ds_ops::ds_break_ctl targets pl2303_break_ctl
+add ds_ops::ds_tx targets pl2303_tx
+add ds_ops::ds_rx targets pl2303_rx
+add ds_ops::ds_stop targets pl2303_stop
+add ds_ops::ds_start targets pl2303_start
+add ds_ops::ds_fifo_flush targets pl2303_fifo_flush
+add ds_ops::ds_fifo_drain targets pl2303_fifo_drain
+
+add pl2303_state::pl_cb.cb_tx targets usbser_tx_cb
+add pl2303_state::pl_cb.cb_rx targets usbser_rx_cb
+
+add usb_ctrl_req::ctrl_cb	targets warlock_dummy
+add usb_ctrl_req::ctrl_exc_cb	targets warlock_dummy
+add usb_bulk_req::bulk_cb	targets pl2303_bulkin_cb
+add usb_bulk_req::bulk_exc_cb	targets pl2303_bulkin_cb
+add usb_bulk_req::bulk_cb	targets pl2303_bulkout_cb
+add usb_bulk_req::bulk_exc_cb	targets pl2303_bulkout_cb
+
+add usb_isoc_req::isoc_cb	targets warlock_dummy
+add usb_isoc_req::isoc_exc_cb	targets warlock_dummy
+add usba_pipe_async_req::callback	targets warlock_dummy
+add usba_pipe_async_req::sync_func	targets warlock_dummy
+add usba_pm_req::cb			targets warlock_dummy
+
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_ctrl_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_bulk_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_intr_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_isoc_td
+
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_bulk_qtd
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_intr_qtd
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_ctrl_qtd
--- a/usr/src/uts/sparc/warlock/Makefile	Mon Nov 14 01:50:26 2005 -0800
+++ b/usr/src/uts/sparc/warlock/Makefile	Mon Nov 14 02:38:25 2005 -0800
@@ -85,6 +85,7 @@
 	@cd ../usbser; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../usbser_edge; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../usbsksp; rm -f *.ll *.ok; $(MAKE) warlock
+	@cd ../usbsprl; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../usbskel; rm -f *.ll *.ok; $(MAKE) warlock
 
 warlock.scsi: