summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/whiteheat.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/whiteheat.c')
-rw-r--r--drivers/usb/serial/whiteheat.c169
1 files changed, 165 insertions, 4 deletions
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index aa6c14b0b..58f761fbf 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1,7 +1,7 @@
/*
* USB ConnectTech WhiteHEAT driver
*
- * (C) Copyright (C) 1999, 2000
+ * Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (05/04/2000) gkh
+ * First cut at open and close commands. Data can flow through the ports at
+ * default speeds now.
+ *
* (03/26/2000) gkh
* Split driver up into device specific pieces.
*
@@ -45,6 +49,7 @@
#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
+#include "whiteheat.h" /* WhiteHEAT specific commands */
#define CONNECT_TECH_VENDOR_ID 0x0710
#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
@@ -57,6 +62,7 @@ static void whiteheat_set_termios (struct usb_serial_port *port, struct termios
static void whiteheat_throttle (struct usb_serial_port *port);
static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_startup (struct usb_serial *serial);
+static void whiteheat_shutdown (struct usb_serial *serial);
/* All of the device info needed for the Connect Tech WhiteHEAT */
static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
@@ -91,14 +97,124 @@ struct usb_serial_device_type whiteheat_device = {
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle,
set_termios: whiteheat_set_termios,
+ shutdown: whiteheat_shutdown,
+};
+
+struct whiteheat_private {
+ __u8 command_finished;
+ wait_queue_head_t wait_command; /* for handling sleeping while waiting for a command to finish */
};
+#define COMMAND_PORT 4
+#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
+
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
*****************************************************************************/
+static void command_port_write_callback (struct urb *urb)
+{
+ unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+ int i;
+#endif
+
+ dbg ("command_port_write_callback");
+
+ if (urb->status) {
+ dbg ("nonzero urb status: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ return;
+}
+
+
+static void command_port_read_callback (struct urb *urb)
+{
+ struct whiteheat_private *info = (struct whiteheat_private *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+ int i;
+#endif
+
+ dbg ("command_port_write_callback");
+
+ if (urb->status) {
+ dbg ("nonzero urb status: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ /* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
+ /* in the future we're going to have to pay attention to the actual command that completed */
+ if (data[0] == WHITEHEAT_CMD_COMPLETE) {
+ info->command_finished = TRUE;
+ }
+
+ return;
+}
+
+
+static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
+{
+ struct whiteheat_private *info;
+ struct usb_serial_port *port;
+ int timeout;
+ __u8 *transfer_buffer;
+
+ dbg("whiteheat_send_cmd: %d", command);
+
+ port = &serial->port[COMMAND_PORT];
+ info = (struct whiteheat_private *)port->private;
+ info->command_finished = FALSE;
+
+ transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
+ transfer_buffer[0] = command;
+ memcpy (&transfer_buffer[1], data, datasize);
+ port->write_urb->transfer_buffer_length = datasize + 1;
+ if (usb_submit_urb (port->write_urb))
+ dbg ("submit urb failed");
+
+ /* wait for the command to complete */
+ timeout = COMMAND_TIMEOUT;
+ while (timeout && (info->command_finished == FALSE)) {
+ timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
+ }
+
+ if (info->command_finished == FALSE) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
+ struct whiteheat_min_set open_command;
+ struct usb_serial_port *command_port;
+ struct whiteheat_private *info;
+
dbg("whiteheat_open port %d", port->number);
if (port->active) {
@@ -106,22 +222,50 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
return -EINVAL;
}
port->active = 1;
-
- /*Start reading from the device*/
+
+ /* set up some stuff for our command port */
+ command_port = &port->serial->port[COMMAND_PORT];
+ if (command_port->private == NULL) {
+ info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+ if (info == NULL) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+
+ init_waitqueue_head(&info->wait_command);
+ command_port->private = info;
+ command_port->write_urb->complete = command_port_write_callback;
+ command_port->read_urb->complete = command_port_read_callback;
+ usb_submit_urb (command_port->read_urb);
+ }
+
+ /* Start reading from the device */
if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
+ /* send an open port command */
+ open_command.port = port->number - port->minor;
+ whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+
/* Need to do device specific setup here (control lines, baud rate, etc.) */
/* FIXME!!! */
+ dbg("whiteheat_open exit");
+
return (0);
}
static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
+ struct whiteheat_min_set close_command;
+
dbg("whiteheat_close port %d", port->number);
+ /* send a close command to the port */
+ close_command.port = port->number - port->minor;
+ whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+
/* Need to change the control lines here */
/* FIXME */
@@ -243,7 +387,24 @@ static int whiteheat_startup (struct usb_serial *serial)
response = ezusb_set_reset (serial, 0);
/* we want this device to fail to have a driver assigned to it. */
- return (1);
+ return 1;
+}
+
+
+static void whiteheat_shutdown (struct usb_serial *serial)
+{
+ struct usb_serial_port *command_port;
+
+ dbg("whiteheat_shutdown");
+
+ /* set up some stuff for our command port */
+ command_port = &serial->port[COMMAND_PORT];
+ if (command_port->private != NULL) {
+ kfree (command_port->private);
+ command_port->private = NULL;
+ }
+
+ return;
}
#endif /* CONFIG_USB_SERIAL_WHITEHEAT */