Mercurial > illumos > illumos-gate
changeset 903:a9ef93192894
6314504 Support for Prolific USB serial adapters
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: