*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
- static int debug = 1;
- #define DEBUG
-#else
- static int debug;
- #undef DEBUG
-#endif
-
#include <linux/usb.h>
-
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "keyspan.h"
+static int debug;
+
/*
* Version Information
*/
/* Per device and per port private data */
struct keyspan_serial_private {
- /* number of active ports */
- atomic_t active_count;
-
const struct keyspan_device_details *device_details;
struct urb *instat_urb;
static void keyspan_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int baud_rate, device_port;
struct keyspan_port_private *p_priv;
/* Write function is similar for the four protocols used
with only a minor change for usa90 (usa19hs) required */
-static int keyspan_write(struct usb_serial_port *port, int from_user,
+static int keyspan_write(struct usb_serial_port *port,
const unsigned char *buf, int count)
{
struct keyspan_port_private *p_priv;
flip = p_priv->out_flip;
/* Check we have a valid urb/endpoint before we use it... */
- if ((this_urb = p_priv->out_urbs[flip]) == 0) {
+ if ((this_urb = p_priv->out_urbs[flip]) == NULL) {
/* no bulk out, so return 0 bytes written */
dbg("%s - no output urb :(", __FUNCTION__);
return count;
dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
if (this_urb->status == -EINPROGRESS) {
- if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
- break;
if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
break;
- this_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_unlink_urb(this_urb);
break;
}
for now so set to zero */
((char *)this_urb->transfer_buffer)[0] = 0;
- if (from_user) {
- if (copy_from_user(this_urb->transfer_buffer + dataOffset, buf, todo))
- return -EFAULT;
- } else {
- memcpy (this_urb->transfer_buffer + dataOffset, buf, todo);
- }
+ memcpy (this_urb->transfer_buffer + dataOffset, buf, todo);
buf += todo;
/* send the data out the bulk port */
this_urb->transfer_buffer_length = todo + dataOffset;
- this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
this_urb->dev = port->serial->dev;
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
dbg("usb_submit_urb(write bulk) failed (%d)", err);
return count - left;
}
-static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
}
/* Outdat handling is common for all devices */
-static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa2x_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]);
if (port->open_count)
- schedule_work(&port->work);
+ usb_serial_port_softint(port);
}
-static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
}
}
-static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_instat_callback(struct urb *urb)
{
unsigned char *data = urb->transfer_buffer;
struct keyspan_usa26_portStatusMessage *msg;
exit: ;
}
-static void usa26_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_glocont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_indat_callback(struct urb *urb)
{
int i, err;
struct usb_serial_port *port;
} while (urb->status != -EINPROGRESS);
}
-static void usa28_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
}
}
-static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_instat_callback(struct urb *urb)
{
int err;
unsigned char *data = urb->transfer_buffer;
exit: ;
}
-static void usa28_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_glocont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_glocont_callback(struct urb *urb)
{
struct usb_serial *serial;
struct usb_serial_port *port;
/* This is actually called glostat in the Keyspan
doco */
-static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_instat_callback(struct urb *urb)
{
int err;
unsigned char *data = urb->transfer_buffer;
exit: ;
}
-static void usa49_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
}
/* not used, usa-49 doesn't have per-port control endpoints */
-static void usa49_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_outcont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
}
-static void usa90_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_instat_callback(struct urb *urb)
{
unsigned char *data = urb->transfer_buffer;
struct keyspan_usa90_portStatusMessage *msg;
;
}
-static void usa90_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
flip = p_priv->out_flip;
/* Check both endpoints to see if any are available. */
- if ((this_urb = p_priv->out_urbs[flip]) != 0) {
+ if ((this_urb = p_priv->out_urbs[flip]) != NULL) {
if (this_urb->status != -EINPROGRESS)
return (data_len);
flip = (flip + 1) & d_details->outdat_endp_flip;
- if ((this_urb = p_priv->out_urbs[flip]) != 0)
+ if ((this_urb = p_priv->out_urbs[flip]) != NULL)
if (this_urb->status != -EINPROGRESS)
return (data_len);
}
static inline void stop_urb(struct urb *urb)
{
- if (urb && urb->status == -EINPROGRESS) {
- urb->transfer_flags &= ~URB_ASYNC_UNLINK;
- usb_unlink_urb(urb);
- }
+ if (urb && urb->status == -EINPROGRESS)
+ usb_kill_urb(urb);
}
static void keyspan_close(struct usb_serial_port *port, struct file *filp)
{
int i;
- struct usb_serial *serial;
+ struct usb_serial *serial = port->serial;
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- serial = get_usb_serial (port, __FUNCTION__);
- if (!serial)
- return;
-
dbg("%s", __FUNCTION__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
stop_urb(p_priv->out_urbs[i]);
}
}
- port->tty = 0;
+ port->tty = NULL;
}
char *fw_name;
dbg("Keyspan startup version %04x product %04x",
- serial->dev->descriptor.bcdDevice,
- serial->dev->descriptor.idProduct);
+ le16_to_cpu(serial->dev->descriptor.bcdDevice),
+ le16_to_cpu(serial->dev->descriptor.idProduct));
- if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
+ if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000) != 0x8000) {
dbg("Firmware already loaded. Quitting.");
return(1);
}
/* Select firmware image on the basis of idProduct */
- switch (serial->dev->descriptor.idProduct) {
+ switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
case keyspan_usa28_pre_product_id:
record = &keyspan_usa28_firmware[0];
fw_name = "USA28";
}
/* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+ int endpoint)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *ep;
+ int i;
+
+ iface_desc = serial->interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ ep = &iface_desc->endpoint[i].desc;
+ if (ep->bEndpointAddress == endpoint)
+ return ep;
+ }
+ dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+ "endpoint %x\n", endpoint);
+ return NULL;
+}
+
static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
- void (*callback)(struct urb *, struct pt_regs *regs))
+ void (*callback)(struct urb *))
{
struct urb *urb;
+ struct usb_endpoint_descriptor const *ep_desc;
+ char const *ep_type_name;
if (endpoint == -1)
return NULL; /* endpoint not needed */
return NULL;
}
- /* Fill URB using supplied data. */
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) | dir,
- buf, len, callback, ctx);
+ ep_desc = find_ep(serial, endpoint);
+ if (!ep_desc) {
+ /* leak the urb, something's wrong and the callers don't care */
+ return urb;
+ }
+ if (usb_endpoint_xfer_int(ep_desc)) {
+ ep_type_name = "INT";
+ usb_fill_int_urb(urb, serial->dev,
+ usb_sndintpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx,
+ ep_desc->bInterval);
+ } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+ ep_type_name = "BULK";
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+ } else {
+ dev_warn(&serial->interface->dev,
+ "unsupported endpoint type %x\n",
+ ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ usb_free_urb(urb);
+ return NULL;
+ }
+ dbg("%s - using urb %p for %s endpoint %x",
+ __func__, urb, ep_type_name, endpoint);
return urb;
}
static struct callbacks {
- void (*instat_callback)(struct urb *, struct pt_regs *regs);
- void (*glocont_callback)(struct urb *, struct pt_regs *regs);
- void (*indat_callback)(struct urb *, struct pt_regs *regs);
- void (*outdat_callback)(struct urb *, struct pt_regs *regs);
- void (*inack_callback)(struct urb *, struct pt_regs *regs);
- void (*outcont_callback)(struct urb *, struct pt_regs *regs);
+ void (*instat_callback)(struct urb *);
+ void (*glocont_callback)(struct urb *);
+ void (*indat_callback)(struct urb *);
+ void (*outdat_callback)(struct urb *);
+ void (*inack_callback)(struct urb *);
+ void (*outcont_callback)(struct urb *);
} keyspan_callbacks[] = {
{
/* msg_usa26 callbacks */
dbg("%s", __FUNCTION__);
for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
- if (d_details->product_id == serial->dev->descriptor.idProduct)
+ if (d_details->product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
break;
if (d_details == NULL) {
- dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __FUNCTION__, serial->dev->descriptor.idProduct);
+ dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __FUNCTION__, le16_to_cpu(serial->dev->descriptor.idProduct));
return 1;
}
/* Setup private data for serial driver */
- s_priv = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+ s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
if (!s_priv) {
dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__);
return -ENOMEM;
}
- memset(s_priv, 0, sizeof(struct keyspan_serial_private));
s_priv->device_details = d_details;
usb_set_serial_data(serial, s_priv);
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
- p_priv = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+ p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
if (!p_priv) {
dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i);
return (1);
}
- memset(p_priv, 0, sizeof(struct keyspan_port_private));
p_priv->device_details = d_details;
usb_set_serial_port_data(port, p_priv);
}
}
/* Now free them */
- if (s_priv->instat_urb)
- usb_free_urb(s_priv->instat_urb);
- if (s_priv->glocont_urb)
- usb_free_urb(s_priv->glocont_urb);
+ usb_free_urb(s_priv->instat_urb);
+ usb_free_urb(s_priv->glocont_urb);
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
p_priv = usb_get_serial_port_data(port);
- if (p_priv->inack_urb)
- usb_free_urb(p_priv->inack_urb);
- if (p_priv->outcont_urb)
- usb_free_urb(p_priv->outcont_urb);
+ usb_free_urb(p_priv->inack_urb);
+ usb_free_urb(p_priv->outcont_urb);
for (j = 0; j < 2; j++) {
- if (p_priv->in_urbs[j])
- usb_free_urb(p_priv->in_urbs[j]);
- if (p_priv->out_urbs[j])
- usb_free_urb(p_priv->out_urbs[j]);
+ usb_free_urb(p_priv->in_urbs[j]);
+ usb_free_urb(p_priv->out_urbs[j]);
}
}
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");