Commit 53b90309 authored by Kristina Martšenko's avatar Kristina Martšenko Committed by Greg Kroah-Hartman

staging: ced1401: remove driver

The state of the driver hasn't improved much since it was added to
staging, and no one with the hardware is currently working on it, so
remove it. This commit can be reverted if someone wants to clean the
driver up and move it to its proper place in the kernel.
Signed-off-by: default avatarKristina Martšenko <kristina.martsenko@gmail.com>
Cc: Greg Smith <greg@ced.co.uk>
Cc: Alois Schlögl <alois.schloegl@ist.ac.at>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 64f488fb
......@@ -106,8 +106,6 @@ source "drivers/staging/gdm724x/Kconfig"
source "drivers/staging/silicom/Kconfig"
source "drivers/staging/ced1401/Kconfig"
source "drivers/staging/imx-drm/Kconfig"
source "drivers/staging/fwserial/Kconfig"
......
......@@ -46,7 +46,6 @@ obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_LTE_GDM724X) += gdm724x/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
obj-$(CONFIG_GOLDFISH) += goldfish/
......
config CED1401
tristate "Cambridge Electronic Design 1401 USB support"
depends on USB
help
This driver supports the Cambridge Electronic Design 1401 USB device
(whatever that is.)
obj-$(CONFIG_CED1401) := cedusb.o
cedusb-objs := usb1401.o ced_ioc.o
TODO:
- coding syle fixes
- build warning fixups
- ioctl auditing
- usb api auditing
- proper USB minor number (it's stomping on an existing one right now.)
Please send patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and Cc:
Alois Schlögl <alois.schloegl@ist.ac.at>
/* ced_ioc.c
ioctl part of the 1401 usb device driver for linux.
Copyright (C) 2010 Cambridge Electronic Design Ltd
Author Greg P Smith (greg@ced.co.uk)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/page-flags.h>
#include <linux/pagemap.h>
#include <linux/jiffies.h>
#include "usb1401.h"
/****************************************************************************
** ced_flush_out_buff
**
** Empties the Output buffer and sets int lines. Used from user level only
****************************************************************************/
static void ced_flush_out_buff(struct ced_data *ced)
{
dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
__func__, ced->current_state);
/* Do nothing if hardware in trouble */
if (ced->current_state == U14ERR_TIME)
return;
/* Kill off any pending I/O */
/* CharSend_Cancel(ced); */
spin_lock_irq(&ced->char_out_lock);
ced->num_output = 0;
ced->out_buff_get = 0;
ced->out_buff_put = 0;
spin_unlock_irq(&ced->char_out_lock);
}
/****************************************************************************
**
** ced_flush_in_buff
**
** Empties the input buffer and sets int lines
****************************************************************************/
static void ced_flush_in_buff(struct ced_data *ced)
{
dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
__func__, ced->current_state);
if (ced->current_state == U14ERR_TIME)
return; /* Do nothing if hardware in trouble */
/* Kill off any pending I/O */
/* CharRead_Cancel(pDevObject); */
spin_lock_irq(&ced->char_in_lock);
ced->num_input = 0;
ced->in_buff_get = 0;
ced->in_buff_put = 0;
spin_unlock_irq(&ced->char_in_lock);
}
/****************************************************************************
** ced_put_chars
**
** Utility routine to copy chars into the output buffer and fire them off.
** called from user mode, holds char_out_lock.
****************************************************************************/
static int ced_put_chars(struct ced_data *ced, const char *ch,
unsigned int count)
{
int ret;
spin_lock_irq(&ced->char_out_lock); /* get the output spin lock */
if ((OUTBUF_SZ - ced->num_output) >= count) {
unsigned int u;
for (u = 0; u < count; u++) {
ced->output_buffer[ced->out_buff_put++] = ch[u];
if (ced->out_buff_put >= OUTBUF_SZ)
ced->out_buff_put = 0;
}
ced->num_output += count;
spin_unlock_irq(&ced->char_out_lock);
/* ...give a chance to transmit data */
ret = ced_send_chars(ced);
} else {
ret = U14ERR_NOOUT; /* no room at the out (ha-ha) */
spin_unlock_irq(&ced->char_out_lock);
}
return ret;
}
/*****************************************************************************
** Add the data in "data" local pointer of length n to the output buffer, and
** trigger an output transfer if this is appropriate. User mode.
** Holds the io_mutex
*****************************************************************************/
int ced_send_string(struct ced_data *ced, const char __user *data,
unsigned int n)
{
int ret = U14ERR_NOERROR; /* assume all will be well */
char buffer[OUTBUF_SZ + 1]; /* space in our address space */
/* for characters */
if (n > OUTBUF_SZ) /* check space in local buffer... */
return U14ERR_NOOUT; /* ...too many characters */
if (copy_from_user(buffer, data, n))
return -EFAULT;
buffer[n] = 0; /* terminate for debug purposes */
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
if (n > 0) { /* do nothing if nowt to do! */
dev_dbg(&ced->interface->dev, "%s: n=%d>%s<\n",
__func__, n, buffer);
ret = ced_put_chars(ced, buffer, n);
}
ced_allowi(ced); /* make sure we have input int */
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_send_char
**
** Sends a single character to the 1401. User mode, holds io_mutex.
****************************************************************************/
int ced_send_char(struct ced_data *ced, char c)
{
int ret;
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
ret = ced_put_chars(ced, &c, 1);
dev_dbg(&ced->interface->dev, "ced_send_char >%c< (0x%02x)\n", c, c);
ced_allowi(ced); /* Make sure char reads are running */
mutex_unlock(&ced->io_mutex);
return ret;
}
/***************************************************************************
**
** ced_get_state
**
** Retrieves state information from the 1401, adjusts the 1401 state held
** in the device extension to indicate the current 1401 type.
**
** *state is updated with information about the 1401 state as returned by the
** 1401. The low byte is a code for what 1401 is doing:
**
** 0 normal 1401 operation
** 1 sending chars to host
** 2 sending block data to host
** 3 reading block data from host
** 4 sending an escape sequence to the host
** 0x80 1401 is executing self-test, in which case the upper word
** is the last error code seen (or zero for no new error).
**
** *error is updated with error information if a self-test error code
** is returned in the upper word of state.
**
** both state and error are set to -1 if there are comms problems, and
** to zero if there is a simple failure.
**
** return error code (U14ERR_NOERROR for OK)
*/
int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error)
{
int got;
dev_dbg(&ced->interface->dev, "%s: entry\n", __func__);
*state = 0xFFFFFFFF; /* Start off with invalid state */
got = usb_control_msg(ced->udev, usb_rcvctrlpipe(ced->udev, 0),
GET_STATUS, (D_TO_H | VENDOR | DEVREQ), 0, 0,
ced->stat_buf, sizeof(ced->stat_buf), HZ);
if (got != sizeof(ced->stat_buf)) {
dev_err(&ced->interface->dev,
"%s: FAILED, return code %d\n", __func__, got);
/* Indicate that things are very wrong indeed */
ced->current_state = U14ERR_TIME;
*state = 0; /* Force status values to a known state */
*error = 0;
} else {
int device;
dev_dbg(&ced->interface->dev,
"%s: Success, state: 0x%x, 0x%x\n",
__func__, ced->stat_buf[0], ced->stat_buf[1]);
/* Return the state values to the calling code */
*state = ced->stat_buf[0];
*error = ced->stat_buf[1];
/* 1401 type code value */
device = ced->udev->descriptor.bcdDevice >> 8;
switch (device) { /* so we can clean up current state */
case 0:
ced->current_state = U14ERR_U1401;
break;
default: /* allow lots of device codes for future 1401s */
if ((device >= 1) && (device <= 23))
ced->current_state = (short)(device + 6);
else
ced->current_state = U14ERR_ILL;
break;
}
}
return ced->current_state >= 0 ? U14ERR_NOERROR : ced->current_state;
}
/****************************************************************************
** ced_read_write_cancel
**
** Kills off staged read\write request from the USB if one is pending.
****************************************************************************/
int ced_read_write_cancel(struct ced_data *ced)
{
dev_dbg(&ced->interface->dev, "%s: entry %d\n",
__func__, ced->staged_urb_pending);
#ifdef NOT_WRITTEN_YET
int ntStatus = STATUS_SUCCESS;
bool bResult = false;
unsigned int i;
/* We can fill this in when we know how we will implement the staged */
/* transfer stuff */
spin_lock_irq(&ced->staged_lock);
if (ced->staged_urb_pending) {/* anything to be cancelled? */
/* May need more... */
dev_info(&ced->interface - dev,
"ced_read_write_cancel about to cancel Urb\n");
/* Clear the staging done flag */
/* KeClearEvent(&ced->StagingDoneEvent); */
USB_ASSERT(ced->pStagedIrp != NULL);
/* Release the spinlock first otherwise the completion */
/* routine may hang on the spinlock while this function */
/* hands waiting for the event. */
spin_unlock_irq(&ced->staged_lock);
/* Actually do the cancel */
bResult = IoCancelIrp(ced->pStagedIrp);
if (bResult) {
LARGE_INTEGER timeout;
/* Use a timeout of 1 second */
timeout.QuadPart = -10000000;
dev_info(&ced->interface - dev,
"%s: about to wait till done\n", __func__);
ntStatus =
KeWaitForSingleObject(&ced->StagingDoneEvent,
Executive, KernelMode, FALSE,
&timeout);
} else {
dev_info(&ced->interface - dev,
"%s: cancellation failed\n", __func__);
ntStatus = U14ERR_FAIL;
}
USB_KdPrint(DBGLVL_DEFAULT,
("ced_read_write_cancel ntStatus = 0x%x decimal %d\n",
ntStatus, ntStatus));
} else
spin_unlock_irq(&ced->staged_lock);
dev_info(&ced->interface - dev, "%s: done\n", __func__);
return ntStatus;
#else
return U14ERR_NOERROR;
#endif
}
/***************************************************************************
** ced_in_self_test - utility to check in self test. Return 1 for ST, 0 for not
** or a -ve error code if we failed for some reason.
***************************************************************************/
static int ced_in_self_test(struct ced_data *ced, unsigned int *stat)
{
unsigned int state, error;
int ret = ced_get_state(ced, &state, &error); /* see if in self-test */
if (ret == U14ERR_NOERROR) /* if all still OK */
ret = (state == (unsigned int)-1) || /* TX problem or... */
((state & 0xff) == 0x80); /* ...self test */
*stat = state; /* return actual state */
return ret;
}
/***************************************************************************
** ced_is_1401 - ALWAYS CALLED HOLDING THE io_mutex
**
** Tests for the current state of the 1401. Sets current_state:
**
** U14ERR_NOIF 1401 i/f card not installed (not done here)
** U14ERR_OFF 1401 apparently not switched on
** U14ERR_NC 1401 appears to be not connected
** U14ERR_ILL 1401 if it is there its not very well at all
** U14ERR_TIME 1401 appears OK, but doesn't communicate - very bad
** U14ERR_STD 1401 OK and ready for use
** U14ERR_PLUS 1401+ OK and ready for use
** U14ERR_U1401 Micro1401 OK and ready for use
** U14ERR_POWER Power1401 OK and ready for use
** U14ERR_U14012 Micro1401 mkII OK and ready for use
**
** Returns TRUE if a 1401 detected and OK, else FALSE
****************************************************************************/
static bool ced_is_1401(struct ced_data *ced)
{
int ret;
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ced_draw_down(ced); /* wait for, then kill outstanding Urbs */
ced_flush_in_buff(ced); /* Clear out input buffer & pipe */
ced_flush_out_buff(ced); /* Clear output buffer & pipe */
/* The next call returns 0 if OK, but has returned 1 in the past, */
/* meaning that usb_unlock_device() is needed... now it always is */
ret = usb_lock_device_for_reset(ced->udev, ced->interface);
/* release the io_mutex because if we don't, we will deadlock due to */
/* system calls back into the driver. */
mutex_unlock(&ced->io_mutex); /* locked, so we will not get */
/* system calls */
if (ret >= 0) { /* if we failed */
ret = usb_reset_device(ced->udev); /* try to do the reset */
usb_unlock_device(ced->udev); /* undo the lock */
}
mutex_lock(&ced->io_mutex); /* hold stuff off while we wait */
ced->dma_flag = MODE_CHAR; /* Clear DMA mode flag regardless! */
if (ret == 0) { /* if all is OK still */
unsigned int state;
ret = ced_in_self_test(ced, &state); /* see if likely in */
/* self test */
if (ret > 0) { /* do we need to wait for self-test? */
/* when to give up */
unsigned long timeout = jiffies + 30 * HZ;
while ((ret > 0) && time_before(jiffies, timeout)) {
schedule(); /* let other stuff run */
/* see if done yet */
ret = ced_in_self_test(ced, &state);
}
}
if (ret == 0) /* if all is OK... */
/* then success is that the state is 0 */
ret = state == 0;
} else
ret = 0; /* we failed */
ced->force_reset = false; /* Clear forced reset flag now */
return ret > 0;
}
/****************************************************************************
** ced_quick_check - ALWAYS CALLED HOLDING THE io_mutex
** This is used to test for a 1401. It will try to do a quick check if all is
** OK, that is the 1401 was OK the last time it was asked, and there is no DMA
** in progress, and if the bTestBuff flag is set, the character buffers must be
** empty too. If the quick check shows that the state is still the same, then
** all is OK.
**
** If any of the above conditions are not met, or if the state or type of the
** 1401 has changed since the previous test, the full ced_is_1401 test is done,
** but only if can_reset is also TRUE.
**
** The return value is TRUE if a useable 1401 is found, FALSE if not
*/
static bool ced_quick_check(struct ced_data *ced, bool test_buff,
bool can_reset)
{
bool ret = false; /* assume it will fail and we will reset */
bool short_test;
short_test = ((ced->dma_flag == MODE_CHAR) && /* no DMA running */
(!ced->force_reset) && /* Not had a real reset forced */
/* No 1401 errors stored */
(ced->current_state >= U14ERR_STD));
dev_dbg(&ced->interface->dev,
"%s: DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d\n",
__func__, ced->dma_flag, ced->current_state, ced->force_reset,
test_buff, short_test);
if ((test_buff) && /* Buffer check requested, and... */
(ced->num_input || ced->num_output)) {/* ...characters were in */
/* the buffer? */
short_test = false; /* Then do the full test */
dev_dbg(&ced->interface->dev,
"%s: will reset as buffers not empty\n", __func__);
}
if (short_test || !can_reset) { /* Still OK to try the short test? */
/* Always test if no reset - we */
/* want state update */
unsigned int state, error;
dev_dbg(&ced->interface->dev, "%s: ced_get_state\n", __func__);
/* Check on the 1401 state */
if (ced_get_state(ced, &state, &error) == U14ERR_NOERROR) {
/* If call worked, check the status value */
if ((state & 0xFF) == 0)
ret = true; /* If that was zero, all is OK, */
/* no reset needed */
}
}
if (!ret && can_reset) { /* If all not OK, then */
dev_info(&ced->interface->dev, "%s: ced_is_1401 %d %d %d %d\n",
__func__, short_test, ced->current_state, test_buff,
ced->force_reset);
ret = ced_is_1401(ced); /* do full test */
}
return ret;
}
/****************************************************************************
** ced_reset
**
** Resets the 1401 and empties the i/o buffers
*****************************************************************************/
int ced_reset(struct ced_data *ced)
{
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
dev_dbg(&ced->interface->dev, "%s: About to call ced_quick_check\n",
__func__);
ced_quick_check(ced, true, true); /* Check 1401, reset if not OK */
mutex_unlock(&ced->io_mutex);
return U14ERR_NOERROR;
}
/****************************************************************************
** ced_get_char
**
** Gets a single character from the 1401
****************************************************************************/
int ced_get_char(struct ced_data *ced)
{
int ret = U14ERR_NOIN; /* assume we will get nothing */
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ced_allowi(ced); /* Make sure char reads are running */
ced_send_chars(ced); /* and send any buffered chars */
spin_lock_irq(&ced->char_in_lock);
if (ced->num_input > 0) { /* worth looking */
ret = ced->input_buffer[ced->in_buff_get++];
if (ced->in_buff_get >= INBUF_SZ)
ced->in_buff_get = 0;
ced->num_input--;
} else
ret = U14ERR_NOIN; /* no input data to read */
spin_unlock_irq(&ced->char_in_lock);
ced_allowi(ced); /* Make sure char reads are running */
mutex_unlock(&ced->io_mutex); /* Protect disconnect from new i/o */
return ret;
}
/****************************************************************************
** ced_get_string
**
** Gets a string from the 1401. Returns chars up to the next CR or when
** there are no more to read or nowhere to put them. CR is translated to
** 0 and counted as a character. If the string does not end in a 0, we will
** add one, if there is room, but it is not counted as a character.
**
** returns the count of characters (including the terminator, or 0 if none
** or a negative error code.
****************************************************************************/
int ced_get_string(struct ced_data *ced, char __user *user, int n)
{
int available; /* character in the buffer */
int ret = U14ERR_NOIN;
if (n <= 0)
return -ENOMEM;
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
ced_allowi(ced); /* Make sure char reads are running */
ced_send_chars(ced); /* and send any buffered chars */
spin_lock_irq(&ced->char_in_lock);
available = ced->num_input; /* characters available now */
if (available > n) /* read max of space in user... */
available = n; /* ...or input characters */
if (available > 0) { /* worth looking? */
char buffer[INBUF_SZ + 1]; /* space for a linear copy of data */
int got = 0;
int n_copy_to_user; /* number to copy to user */
char data;
do {
data = ced->input_buffer[ced->in_buff_get++];
if (data == CR_CHAR) /* replace CR with zero */
data = (char)0;
if (ced->in_buff_get >= INBUF_SZ)
ced->in_buff_get = 0; /* wrap buffer pointer */
buffer[got++] = data; /* save the output */
} while ((got < available) && data);
n_copy_to_user = got; /* what to copy... */
if (data) { /* do we need null */
buffer[got] = (char)0; /* make it tidy */
if (got < n) /* if space in user buffer... */
++n_copy_to_user; /* ...copy the 0 as well. */
}
ced->num_input -= got;
spin_unlock_irq(&ced->char_in_lock);
dev_dbg(&ced->interface->dev, "%s: read %d characters >%s<\n",
__func__, got, buffer);
if (copy_to_user(user, buffer, n_copy_to_user))
ret = -EFAULT;
else
ret = got; /* report characters read */
} else
spin_unlock_irq(&ced->char_in_lock);
ced_allowi(ced); /* Make sure char reads are running */
mutex_unlock(&ced->io_mutex); /* Protect disconnect from new i/o */
return ret;
}
/*******************************************************************************
** Get count of characters in the inout buffer.
*******************************************************************************/
int ced_stat_1401(struct ced_data *ced)
{
int ret;
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
ced_allowi(ced); /* make sure we allow pending chars */
ced_send_chars(ced); /* in both directions */
ret = ced->num_input; /* no lock as single read */
mutex_unlock(&ced->io_mutex); /* Protect disconnect from new i/o */
return ret;
}
/****************************************************************************
** ced_line_count
**
** Returns the number of newline chars in the buffer. There is no need for
** any fancy interlocks as we only read the interrupt routine data, and the
** system is arranged so nothing can be destroyed.
****************************************************************************/
int ced_line_count(struct ced_data *ced)
{
int ret = 0; /* will be count of line ends */
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
ced_allowi(ced); /* Make sure char reads are running */
ced_send_chars(ced); /* and send any buffered chars */
spin_lock_irq(&ced->char_in_lock); /* Get protection */
if (ced->num_input > 0) { /* worth looking? */
/* start at first available */
unsigned int index = ced->in_buff_get;
/* Position for search end */
unsigned int end = ced->in_buff_put;
do {
if (ced->input_buffer[index++] == CR_CHAR)
++ret; /* inc count if CR */
if (index >= INBUF_SZ) /* see if we fall off buff */
index = 0;
} while (index != end); /* go to last available */
}
spin_unlock_irq(&ced->char_in_lock);
dev_dbg(&ced->interface->dev, "%s: returned %d\n", __func__, ret);
mutex_unlock(&ced->io_mutex); /* Protect disconnect from new i/o */
return ret;
}
/****************************************************************************
** ced_get_out_buf_space
**
** Gets the space in the output buffer. Called from user code.
*****************************************************************************/
int ced_get_out_buf_space(struct ced_data *ced)
{
int ret;
mutex_lock(&ced->io_mutex); /* Protect disconnect from new i/o */
ced_send_chars(ced); /* send any buffered chars */
/* no lock needed for single read */
ret = (int)(OUTBUF_SZ - ced->num_output);
dev_dbg(&ced->interface->dev, "%s: %d\n", __func__, ret);
mutex_unlock(&ced->io_mutex); /* Protect disconnect from new i/o */
return ret;
}
/****************************************************************************
**
** ced_clear_area
**
** Clears up a transfer area. This is always called in the context of a user
** request, never from a call-back.
****************************************************************************/
int ced_clear_area(struct ced_data *ced, int area)
{
int ret = U14ERR_NOERROR;
if ((area < 0) || (area >= MAX_TRANSAREAS)) {
ret = U14ERR_BADAREA;
dev_err(&ced->interface->dev, "%s: Attempt to clear area %d\n",
__func__, area);
} else {
/* to save typing */
struct transarea *ta = &ced->trans_def[area];
if (!ta->used) /* if not used... */
ret = U14ERR_NOTSET; /* ...nothing to be done */
else {
/* We must save the memory we return as we shouldn't */
/* mess with memory while holding a spin lock. */
struct page **pages = NULL; /*save page address list*/
int n_pages = 0; /* and number of pages */
int np;
dev_dbg(&ced->interface->dev, "%s: area %d\n",
__func__, area);
spin_lock_irq(&ced->staged_lock);
if ((ced->staged_id == area)
&& (ced->dma_flag > MODE_CHAR)) {
/* cannot delete as in use */
ret = U14ERR_UNLOCKFAIL;
dev_err(&ced->interface->dev,
"%s: call on area %d while active\n",
__func__, area);
} else {
pages = ta->pages; /* save page address list */
n_pages = ta->n_pages; /* and page count */
if (ta->event_sz)/* if events flagging in use */
/* release anything that was waiting */
wake_up_interruptible(&ta->event);
if (ced->xfer_waiting
&& (ced->dma_info.ident == area))
/* Cannot have pending xfer if */
/* area cleared */
ced->xfer_waiting = false;
/* Clean out the struct transarea except for */
/* the wait queue, which is at the end. This */
/* sets used to false and event_sz to 0 to */
/* say area not used and no events. */
memset(ta, 0,
sizeof(struct transarea) -
sizeof(wait_queue_head_t));
}
spin_unlock_irq(&ced->staged_lock);
if (pages) { /* if we decided to release the memory */
/* Now we must undo the pinning down of the */
/* pages. We will assume the worst and mark */
/* all the pages as dirty. Don't be tempted */
/* to move this up above as you must not be */
/* holding a spin lock to do this stuff as */
/* it is not atomic. */
dev_dbg(&ced->interface->dev,
"%s: n_pages=%d\n",
__func__, n_pages);
for (np = 0; np < n_pages; ++np) {
if (pages[np]) {
SetPageDirty(pages[np]);
page_cache_release(pages[np]);
}
}
kfree(pages);
dev_dbg(&ced->interface->dev,
"%s: kfree(pages) done\n", __func__);
}
}
}
return ret;
}
/****************************************************************************
** ced_set_area
**
** Sets up a transfer area - the functional part. Called by both
** ced_set_transfer and ced_set_circular.
****************************************************************************/
static int ced_set_area(struct ced_data *ced, int area, char __user *buf,
unsigned int length, bool circular, bool circ_to_host)
{
/* Start by working out the page aligned start of the area and the */
/* size of the area in pages, allowing for the start not being */
/* aligned and the end needing to be rounded up to a page boundary. */
unsigned long start = ((unsigned long)buf) & PAGE_MASK;
unsigned int offset = ((unsigned long)buf) & (PAGE_SIZE - 1);
int len = (length + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
struct transarea *ta = &ced->trans_def[area]; /* to save typing */
struct page **pages = NULL; /* space for page tables */
int n_pages = 0; /* and number of pages */
int ret = ced_clear_area(ced, area); /* see if OK to use this area */
if ((ret != U14ERR_NOTSET) && /* if not area unused and... */
(ret != U14ERR_NOERROR)) /* ...not all OK, then... */
return ret; /* ...we cannot use this area */
/* if we cannot access the memory... */
if (!access_ok(VERIFY_WRITE, buf, length))
return -EFAULT; /* ...then we are done */
/* Now allocate space to hold the page pointer and */
/* virtual address pointer tables */
pages = kmalloc(len * sizeof(struct page *), GFP_KERNEL);
if (!pages) {
ret = U14ERR_NOMEMORY;
goto error;
}
dev_dbg(&ced->interface->dev, "%s: %p, length=%06x, circular %d\n",
__func__, buf, length, circular);
/* To pin down user pages we must first */
/* acquire the mapping semaphore. */
n_pages = get_user_pages_fast(start, len, 1, pages);
dev_dbg(&ced->interface->dev, "%s: n_pages = %d\n", __func__, n_pages);
if (n_pages > 0) { /* if we succeeded */
/* If you are tempted to use page_address (form LDD3), forget */
/* it. You MUST use kmap() or kmap_atomic() to get a virtual */
/* address. page_address will give you (null) or at least it */
/* does in this context with an x86 machine. */
spin_lock_irq(&ced->staged_lock);
ta->buff = buf; /* keep start of region (user address) */
ta->base_offset = offset; /* save offset in first page */
/* to start of xfer */
ta->length = length; /* Size if the region in bytes */
ta->pages = pages; /* list of pages that are used by buffer */
ta->n_pages = n_pages; /* number of pages */
ta->circular = circular;
ta->circ_to_host = circ_to_host;
ta->blocks[0].offset = 0;
ta->blocks[0].size = 0;
ta->blocks[1].offset = 0;
ta->blocks[1].size = 0;
ta->used = true; /* This is now a used block */
spin_unlock_irq(&ced->staged_lock);
ret = U14ERR_NOERROR; /* say all was well */
} else {
ret = U14ERR_LOCKFAIL;
goto error;
}
return ret;
error:
kfree(pages);
return ret;
}
/****************************************************************************
** ced_set_transfer
**
** Sets up a transfer area record. If the area is already set, we attempt to
** unset it. Unsetting will fail if the area is booked, and a transfer to that
** area is in progress. Otherwise, we will release the area and re-assign it.
****************************************************************************/
int ced_set_transfer(struct ced_data *ced,
struct transfer_area_desc __user *utd)
{
int ret;
struct transfer_area_desc td;
if (copy_from_user(&td, utd, sizeof(td)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: area:%d, size:%08x\n",
__func__, td.wAreaNum, td.dwLength);
/* The strange cast is done so that we don't get warnings in 32-bit */
/* linux about the size of the pointer. The pointer is always passed */
/* as a 64-bit object so that we don't have problems using a 32-bit */
/* program on a 64-bit system. unsigned long is 64-bits on a 64-bit */
/* system. */
ret =
ced_set_area(ced, td.wAreaNum,
(char __user *)((unsigned long)td.lpvBuff), td.dwLength,
false, false);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_unset_transfer
** Erases a transfer area record
****************************************************************************/
int ced_unset_transfer(struct ced_data *ced, int area)
{
int ret;
mutex_lock(&ced->io_mutex);
ret = ced_clear_area(ced, area);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_set_event
** Creates an event that we can test for based on a transfer to/from an area.
** The area must be setup for a transfer. We attempt to simulate the Windows
** driver behavior for events (as we don't actually use them), which is to
** pretend that whatever the user asked for was achieved, so we return 1 if
** try to create one, and 0 if they ask to remove (assuming all else was OK).
****************************************************************************/
int ced_set_event(struct ced_data *ced, struct transfer_event __user *ute)
{
int ret = U14ERR_NOERROR;
struct transfer_event te;
struct transarea *ta;
/* get a local copy of the data */
if (copy_from_user(&te, ute, sizeof(te)))
return -EFAULT;
if (te.wAreaNum >= MAX_TRANSAREAS) /* the area must exist */
return U14ERR_BADAREA;
ta = &ced->trans_def[te.wAreaNum];
/* make sure we have no competitor */
mutex_lock(&ced->io_mutex);
spin_lock_irq(&ced->staged_lock);
if (ta->used) { /* area must be in use */
ta->event_st = te.dwStart; /* set area regions */
/* set size (0 cancels it) */
ta->event_sz = te.dwLength;
/* set the direction */
ta->event_to_host = te.wFlags & 1;
ta->wake_up = 0; /* zero the wake up count */
} else
ret = U14ERR_NOTSET;
spin_unlock_irq(&ced->staged_lock);
mutex_unlock(&ced->io_mutex);
return ret ==
U14ERR_NOERROR ? (te.iSetEvent ? 1 : U14ERR_NOERROR) : ret;
}
/****************************************************************************
** ced_wait_event
** Sleep the process with a timeout waiting for an event. Returns the number
** of times that a block met the event condition since we last cleared it or
** 0 if timed out, or -ve error (bad area or not set, or signal).
****************************************************************************/
int ced_wait_event(struct ced_data *ced, int area, int time_out)
{
int ret;
int wait;
struct transarea *ta;
if ((unsigned)area >= MAX_TRANSAREAS)
return U14ERR_BADAREA;
ta = &ced->trans_def[area];
/* convert timeout to jiffies */
time_out = (time_out * HZ + 999) / 1000;
/* We cannot wait holding the mutex, but we check the flags */
/* while holding it. This may well be pointless as another */
/* thread could get in between releasing it and the wait */
/* call. However, this would have to clear the wake_up flag. */
/* However, the !ta->used may help us in this case. */
/* make sure we have no competitor */
mutex_lock(&ced->io_mutex);
if (!ta->used || !ta->event_sz) /* check something to */
/* wait for... */
return U14ERR_NOTSET; /* ...else we do nothing */
mutex_unlock(&ced->io_mutex);
if (time_out)
wait = wait_event_interruptible_timeout(ta->event,
ta->wake_up ||
!ta->used,
time_out);
else
wait = wait_event_interruptible(ta->event,
ta->wake_up ||
!ta->used);
if (wait)
ret = -ERESTARTSYS; /* oops - we have had a SIGNAL */
else
ret = ta->wake_up; /* else the wakeup count */
spin_lock_irq(&ced->staged_lock);
ta->wake_up = 0; /* clear the flag */
spin_unlock_irq(&ced->staged_lock);
return ret;
}
/****************************************************************************
** ced_test_event
** Test the event to see if a ced_wait_event would return immediately. Returns
** the number of times a block completed since the last call, or 0 if none or a
** negative error.
****************************************************************************/
int ced_test_event(struct ced_data *ced, int area)
{
int ret;
if ((unsigned)area >= MAX_TRANSAREAS)
ret = U14ERR_BADAREA;
else {
struct transarea *ta = &ced->trans_def[area];
/* make sure we have no competitor */
mutex_lock(&ced->io_mutex);
spin_lock_irq(&ced->staged_lock);
ret = ta->wake_up; /* get wakeup count since last call */
ta->wake_up = 0; /* clear the count */
spin_unlock_irq(&ced->staged_lock);
mutex_unlock(&ced->io_mutex);
}
return ret;
}
/****************************************************************************
** ced_get_transferInfo
** Puts the current state of the 1401 in a TGET_TX_BLOCK.
*****************************************************************************/
int ced_get_transfer(struct ced_data *ced, TGET_TX_BLOCK __user *utx)
{
int ret = U14ERR_NOERROR;
unsigned int dwIdent;
mutex_lock(&ced->io_mutex);
dwIdent = ced->staged_id; /* area ident for last xfer */
if (dwIdent >= MAX_TRANSAREAS)
ret = U14ERR_BADAREA;
else {
/* Return the best information we have - we */
/* don't have physical addresses */
TGET_TX_BLOCK *tx;
tx = kzalloc(sizeof(*tx), GFP_KERNEL);
if (!tx) {
mutex_unlock(&ced->io_mutex);
return -ENOMEM;
}
tx->size = ced->trans_def[dwIdent].length;
tx->linear = (long long)((long)ced->trans_def[dwIdent].buff);
/* how many blocks we could return */
tx->avail = GET_TX_MAXENTRIES;
tx->used = 1; /* number we actually return */
tx->entries[0].physical =
(long long)(tx->linear + ced->staged_offset);
tx->entries[0].size = tx->size;
if (copy_to_user(utx, tx, sizeof(*tx)))
ret = -EFAULT;
kfree(tx);
}
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_kill_io
**
** Empties the host i/o buffers
****************************************************************************/
int ced_kill_io(struct ced_data *ced)
{
dev_dbg(&ced->interface->dev, "%s\n", __func__);
mutex_lock(&ced->io_mutex);
ced_flush_out_buff(ced);
ced_flush_in_buff(ced);
mutex_unlock(&ced->io_mutex);
return U14ERR_NOERROR;
}
/****************************************************************************
** ced_state_of_1401
**
** Puts the current state of the 1401 in the Irp return buffer.
*****************************************************************************/
int ced_state_of_1401(struct ced_data *ced)
{
int ret;
mutex_lock(&ced->io_mutex);
ced_quick_check(ced, false, false); /* get state up to date, no reset */
ret = ced->current_state;
mutex_unlock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: %d\n", __func__, ret);
return ret;
}
/****************************************************************************
** ced_start_self_test
**
** Initiates a self-test cycle. The assumption is that we have no interrupts
** active, so we should make sure that this is the case.
*****************************************************************************/
int ced_start_self_test(struct ced_data *ced)
{
int got;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ced_draw_down(ced); /* wait for, then kill outstanding Urbs */
ced_flush_in_buff(ced); /* Clear out input buffer & pipe */
ced_flush_out_buff(ced); /* Clear output buffer & pipe */
/* so things stay tidy */
/* ced_read_write_cancel(pDeviceObject); */
ced->dma_flag = MODE_CHAR; /* Clear DMA mode flags here */
got = usb_control_msg(ced->udev, usb_rcvctrlpipe(ced->udev, 0),
DB_SELFTEST, (H_TO_D | VENDOR | DEVREQ),
0, 0, NULL, 0, HZ); /* allow 1 second timeout */
ced->self_test_time = jiffies + HZ * 30; /* 30 seconds into the */
/* future */
mutex_unlock(&ced->io_mutex);
if (got < 0)
dev_err(&ced->interface->dev, "%s: err=%d\n", __func__, got);
return got < 0 ? U14ERR_FAIL : U14ERR_NOERROR;
}
/****************************************************************************
** ced_check_self_test
**
** Check progress of a self-test cycle
****************************************************************************/
int ced_check_self_test(struct ced_data *ced, TGET_SELFTEST __user *ugst)
{
unsigned int state, error;
int ret;
TGET_SELFTEST gst; /* local work space */
memset(&gst, 0, sizeof(gst)); /* clear out the space (sets code 0) */
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ret = ced_get_state(ced, &state, &error);
if (ret == U14ERR_NOERROR) /* Only accept zero if it happens twice */
ret = ced_get_state(ced, &state, &error);
if (ret != U14ERR_NOERROR) { /* Self-test can cause comms errors */
/* so we assume still testing */
dev_err(&ced->interface->dev,
"%s: ced_get_state=%d, assuming still testing\n",
__func__, ret);
state = 0x80; /* Force still-testing, no error */
error = 0;
ret = U14ERR_NOERROR;
}
if ((state == -1) && (error == -1)) {/* If ced_get_state had problems */
dev_err(&ced->interface->dev,
"%s: ced_get_state failed, assuming still testing\n",
__func__);
state = 0x80; /* Force still-testing, no error */
error = 0;
}
if ((state & 0xFF) == 0x80) { /* If we are still in self-test */
if (state & 0x00FF0000) { /* Have we got an error? */
/* read the error code */
gst.code = (state & 0x00FF0000) >> 16;
gst.x = error & 0x0000FFFF; /* Error data X */
gst.y = (error & 0xFFFF0000) >> 16; /* and data Y */
dev_dbg(&ced->interface->dev,
"Self-test error code %d\n", gst.code);
} else { /* No error, check for timeout */
unsigned long now = jiffies; /* get current time */
if (time_after(now, ced->self_test_time)) {
gst.code = -2; /* Flag the timeout */
dev_dbg(&ced->interface->dev,
"Self-test timed-out\n");
} else
dev_dbg(&ced->interface->dev,
"Self-test on-going\n");
}
} else {
gst.code = -1; /* Flag the test is done */
dev_dbg(&ced->interface->dev, "Self-test done\n");
}
if (gst.code < 0) { /* If we have a problem or finished */
/* If using the 2890 we should reset properly */
if ((ced->n_pipes == 4) && (ced->type <= TYPEPOWER))
ced_is_1401(ced); /* Get 1401 reset and OK */
else
/* Otherwise check without reset unless problems */
ced_quick_check(ced, true, true);
}
mutex_unlock(&ced->io_mutex);
if (copy_to_user(ugst, &gst, sizeof(gst)))
return -EFAULT;
return ret;
}
/****************************************************************************
** ced_type_of_1401
**
** Returns code for standard, plus, micro1401, power1401 or none
****************************************************************************/
int ced_type_of_1401(struct ced_data *ced)
{
int ret = TYPEUNKNOWN;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
switch (ced->type) {
case TYPE1401:
ret = U14ERR_STD;
break; /* Handle these types directly */
case TYPEPLUS:
ret = U14ERR_PLUS;
break;
case TYPEU1401:
ret = U14ERR_U1401;
break;
default:
if ((ced->type >= TYPEPOWER) && (ced->type <= 25))
ret = ced->type + 4; /* We can calculate types */
else /* for up-coming 1401 designs */
ret = TYPEUNKNOWN; /* Don't know or not there */
}
dev_dbg(&ced->interface->dev, "%s %d\n", __func__, ret);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_transfer_flags
**
** Returns flags on block transfer abilities
****************************************************************************/
int ced_transfer_flags(struct ced_data *ced)
{
/* we always have multiple DMA area diagnostics, notify and circular */
int ret = U14TF_MULTIA | U14TF_DIAG |
U14TF_NOTIFY | U14TF_CIRCTH;
dev_dbg(&ced->interface->dev, "%s\n", __func__);
mutex_lock(&ced->io_mutex);
if (ced->is_usb2) /* Set flag for USB2 if appropriate */
ret |= U14TF_USB2;
mutex_unlock(&ced->io_mutex);
return ret;
}
/***************************************************************************
** ced_dbg_cmd
** Issues a debug\diagnostic command to the 1401 along with a 32-bit datum
** This is a utility command used for dbg operations.
*/
static int ced_dbg_cmd(struct ced_data *ced, unsigned char cmd,
unsigned int data)
{
int ret;
dev_dbg(&ced->interface->dev, "%s: entry\n", __func__);
ret = usb_control_msg(ced->udev, usb_sndctrlpipe(ced->udev, 0), cmd,
(H_TO_D | VENDOR | DEVREQ),
(unsigned short)data,
(unsigned short)(data >> 16), NULL, 0, HZ);
/* allow 1 second timeout */
if (ret < 0)
dev_err(&ced->interface->dev, "%s: fail code=%d\n",
__func__, ret);
return ret;
}
/****************************************************************************
** ced_dbg_peek
**
** Execute the diagnostic peek operation. Uses address, width and repeats.
****************************************************************************/
int ced_dbg_peek(struct ced_data *ced, TDBGBLOCK __user *udb)
{
int ret;
TDBGBLOCK db;
if (copy_from_user(&db, udb, sizeof(db)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
ret = ced_dbg_cmd(ced, DB_SETADD, db.iAddr);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_WIDTH, db.iWidth);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_REPEATS, db.iRepeats);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_PEEK, 0);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_dbg_poke
**
** Execute the diagnostic poke operation. Parameters are in the CSBLOCK struct
** in order address, size, repeats and value to poke.
****************************************************************************/
int ced_dbg_poke(struct ced_data *ced, TDBGBLOCK __user *udb)
{
int ret;
TDBGBLOCK db;
if (copy_from_user(&db, udb, sizeof(db)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
ret = ced_dbg_cmd(ced, DB_SETADD, db.iAddr);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_WIDTH, db.iWidth);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_REPEATS, db.iRepeats);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_POKE, db.iData);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_dbg_ramp_data
**
** Execute the diagnostic ramp data operation. Parameters are in the CSBLOCK
** struct in order address, default, enable mask, size and repeats.
****************************************************************************/
int ced_dbg_ramp_data(struct ced_data *ced, TDBGBLOCK __user *udb)
{
int ret;
TDBGBLOCK db;
if (copy_from_user(&db, udb, sizeof(db)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
ret = ced_dbg_cmd(ced, DB_SETADD, db.iAddr);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_SETDEF, db.iDefault);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_SETMASK, db.iMask);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_WIDTH, db.iWidth);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_REPEATS, db.iRepeats);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_RAMPD, 0);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_dbg_ramp_addr
**
** Execute the diagnostic ramp address operation
****************************************************************************/
int ced_dbg_ramp_addr(struct ced_data *ced, TDBGBLOCK __user *udb)
{
int ret;
TDBGBLOCK db;
if (copy_from_user(&db, udb, sizeof(db)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ret = ced_dbg_cmd(ced, DB_SETDEF, db.iDefault);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_SETMASK, db.iMask);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_WIDTH, db.iWidth);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_REPEATS, db.iRepeats);
if (ret == U14ERR_NOERROR)
ret = ced_dbg_cmd(ced, DB_RAMPA, 0);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_dbg_get_data
**
** Retrieve the data resulting from the last debug Peek operation
****************************************************************************/
int ced_dbg_get_data(struct ced_data *ced, TDBGBLOCK __user *udb)
{
int ret;
TDBGBLOCK db;
memset(&db, 0, sizeof(db)); /* fill returned block with 0s */
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
/* Read back the last peeked value from the 1401. */
ret = usb_control_msg(ced->udev, usb_rcvctrlpipe(ced->udev, 0),
DB_DATA, (D_TO_H | VENDOR | DEVREQ), 0, 0,
&db.iData, sizeof(db.iData), HZ);
if (ret == sizeof(db.iData)) {
if (copy_to_user(udb, &db, sizeof(db)))
ret = -EFAULT;
else
ret = U14ERR_NOERROR;
} else
dev_err(&ced->interface->dev, "%s: failed, code %d\n",
__func__, ret);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_dbg_stop_loop
**
** Stop any never-ending debug loop, we just call ced_get_state for USB
**
****************************************************************************/
int ced_dbg_stop_loop(struct ced_data *ced)
{
int ret;
unsigned int uState, uErr;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
ret = ced_get_state(ced, &uState, &uErr);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_set_circular
**
** Sets up a transfer area record for circular transfers. If the area is
** already set, we attempt to unset it. Unsetting will fail if the area is
** booked and a transfer to that area is in progress. Otherwise, we will
** release the area and re-assign it.
****************************************************************************/
int ced_set_circular(struct ced_data *ced,
struct transfer_area_desc __user *utd)
{
int ret;
bool to_host;
struct transfer_area_desc td;
if (copy_from_user(&td, utd, sizeof(td)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: area:%d, size:%08x\n",
__func__, td.wAreaNum, td.dwLength);
to_host = td.eSize != 0; /* this is used as the tohost flag */
/* The strange cast is done so that we don't get warnings in 32-bit */
/* linux about the size of the pointer. The pointer is always passed */
/* as a 64-bit object so that we don't have problems using a 32-bit */
/* program on a 64-bit system. unsigned long is 64-bits on a 64-bit */
/* system. */
ret =
ced_set_area(ced, td.wAreaNum,
(char __user *)((unsigned long)td.lpvBuff), td.dwLength,
true, to_host);
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_get_circ_block
**
** Return the next available block of circularly-transferred data.
****************************************************************************/
int ced_get_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb)
{
int ret = U14ERR_NOERROR;
unsigned int area;
TCIRCBLOCK cb;
dev_dbg(&ced->interface->dev, "%s\n", __func__);
if (copy_from_user(&cb, ucb, sizeof(cb)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
area = cb.nArea; /* Retrieve parameters first */
cb.dwOffset = 0; /* set default result (nothing) */
cb.dwSize = 0;
if (area < MAX_TRANSAREAS) { /* The area number must be OK */
/* Pointer to relevant info */
struct transarea *ta = &ced->trans_def[area];
spin_lock_irq(&ced->staged_lock); /* Lock others out */
if ((ta->used) && (ta->circular) && /* Must be circular area */
(ta->circ_to_host)) { /* For now at least must be to host */
if (ta->blocks[0].size > 0) { /* Got anything? */
cb.dwOffset = ta->blocks[0].offset;
cb.dwSize = ta->blocks[0].size;
dev_dbg(&ced->interface->dev,
"%s: return block 0: %d bytes at %d\n",
__func__, cb.dwSize, cb.dwOffset);
}
} else
ret = U14ERR_NOTSET;
spin_unlock_irq(&ced->staged_lock);
} else
ret = U14ERR_BADAREA;
if (copy_to_user(ucb, &cb, sizeof(cb)))
ret = -EFAULT;
mutex_unlock(&ced->io_mutex);
return ret;
}
/****************************************************************************
** ced_free_circ_block
**
** Frees a block of circularly-transferred data and returns the next one.
****************************************************************************/
int ced_free_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb)
{
int ret = U14ERR_NOERROR;
unsigned int area, start, size;
TCIRCBLOCK cb;
dev_dbg(&ced->interface->dev, "%s\n", __func__);
if (copy_from_user(&cb, ucb, sizeof(cb)))
return -EFAULT;
mutex_lock(&ced->io_mutex);
area = cb.nArea; /* Retrieve parameters first */
start = cb.dwOffset;
size = cb.dwSize;
cb.dwOffset = 0; /* then set default result (nothing) */
cb.dwSize = 0;
if (area < MAX_TRANSAREAS) { /* The area number must be OK */
/* Pointer to relevant info */
struct transarea *ta = &ced->trans_def[area];
spin_lock_irq(&ced->staged_lock); /* Lock others out */
if ((ta->used) && (ta->circular) && /* Must be circular area */
(ta->circ_to_host)) { /* For now at least must be to host */
bool waiting = false;
if ((ta->blocks[0].size >= size) && /* Got anything? */
/* Must be legal data */
(ta->blocks[0].offset == start)) {
ta->blocks[0].size -= size;
ta->blocks[0].offset += size;
/* Have we emptied this block? */
if (ta->blocks[0].size == 0) {
/* Is there a second block? */
if (ta->blocks[1].size) {
/* Copy down block 2 data */
ta->blocks[0] = ta->blocks[1];
/* and mark the second */
/* block as unused */
ta->blocks[1].size = 0;
ta->blocks[1].offset = 0;
} else
ta->blocks[0].offset = 0;
}
dev_dbg(&ced->interface->dev,
"%s: free %d bytes at %d, "
"return %d bytes at %d, wait=%d\n",
__func__, size, start,
ta->blocks[0].size,
ta->blocks[0].offset,
ced->xfer_waiting);
/* Return the next available block of */
/* memory as well */
if (ta->blocks[0].size > 0) {/* Got anything? */
cb.dwOffset =
ta->blocks[0].offset;
cb.dwSize = ta->blocks[0].size;
}
waiting = ced->xfer_waiting;
if (waiting && ced->staged_urb_pending) {
dev_err(&ced->interface->dev,
"%s: ERROR: waiting xfer and "
"staged Urb pending!\n",
__func__);
waiting = false;
}
} else {
dev_err(&ced->interface->dev,
"%s: ERROR: freeing %d bytes at %d, "
"block 0 is %d bytes at %d\n",
__func__, size, start,
ta->blocks[0].size,
ta->blocks[0].offset);
ret = U14ERR_NOMEMORY;
}
/* If we have one, kick off pending transfer */
if (waiting) { /* Got a block xfer waiting? */
int RWMStat =
ced_read_write_mem(ced,
!ced->dma_info.outward,
ced->dma_info.ident,
ced->dma_info.offset,
ced->dma_info.size);
if (RWMStat != U14ERR_NOERROR)
dev_err(&ced->interface->dev,
"%s: rw setup failed %d\n",
__func__, RWMStat);
}
} else
ret = U14ERR_NOTSET;
spin_unlock_irq(&ced->staged_lock);
} else
ret = U14ERR_BADAREA;
if (copy_to_user(ucb, &cb, sizeof(cb)))
ret = -EFAULT;
mutex_unlock(&ced->io_mutex);
return ret;
}
/*
* IOCTL calls for the CED1401 driver
* Copyright (C) 2010 Cambridge Electronic Design Ltd
* Author Greg P Smith (greg@ced.co.uk)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __CED_IOCTL_H__
#define __CED_IOCTL_H__
#include <linux/ioctl.h>
/* dma modes, only MODE_CHAR and MODE_LINEAR are used in this driver */
#define MODE_CHAR 0
#define MODE_LINEAR 1
/****************************************************************************
** TypeDefs
*****************************************************************************/
struct transfer_area_desc {
long long lpvBuff; /* address of transfer area (for 64 or 32 bit) */
unsigned int dwLength; /* length of the area */
unsigned short wAreaNum; /* number of transfer area to set up */
short eSize; /* element size - is tohost flag for circular */
};
struct transfer_event {
unsigned int dwStart; /* offset into the area */
unsigned int dwLength; /* length of the region */
unsigned short wAreaNum; /* the area number */
unsigned short wFlags; /* bit 0 set for toHost */
int iSetEvent; /* could be dummy in LINUX */
};
#define MAX_TRANSFER_SIZE 0x4000 /* Maximum data bytes per IRP */
#define MAX_AREA_LENGTH 0x100000 /* Maximum size of transfer area */
#define MAX_TRANSAREAS 8 /* definitions for dma set up */
typedef struct TGetSelfTest {
int code; /* self-test error code */
int x, y; /* additional information */
} TGET_SELFTEST;
/* Debug block used for several commands. Not all fields are used for all commands. */
typedef struct TDbgBlock {
int iAddr; /* the address in the 1401 */
int iRepeats; /* number of repeats */
int iWidth; /* width in bytes 1, 2, 4 */
int iDefault; /* default value */
int iMask; /* mask to apply */
int iData; /* data for poke, result for peek */
} TDBGBLOCK;
/* Used to collect information about a circular block from the device driver */
typedef struct TCircBlock {
unsigned int nArea; /* the area to collect information from */
unsigned int dwOffset; /* offset into the area to the available block */
unsigned int dwSize; /* size of the area */
} TCIRCBLOCK;
/* Used to clollect the 1401 status */
typedef struct TCSBlock {
unsigned int uiState;
unsigned int uiError;
} TCSBLOCK;
/*
* As seen by the user, an ioctl call looks like: int ioctl(int fd, unsigned
* long cmd, char* argp); We will then have all sorts of variants on this that
* can be used to pass stuff to our driver. We will generate macros for each
* type of call so as to provide some sort of type safety in the calling:
*/
#define CED_MAGIC_IOC 0xce
#define IOCTL_CED_SENDSTRING(n) _IOC(_IOC_WRITE, CED_MAGIC_IOC, 2, n)
#define IOCTL_CED_RESET1401 _IO(CED_MAGIC_IOC, 3)
#define IOCTL_CED_GETCHAR _IO(CED_MAGIC_IOC, 4)
#define IOCTL_CED_SENDCHAR _IO(CED_MAGIC_IOC, 5)
#define IOCTL_CED_STAT1401 _IO(CED_MAGIC_IOC, 6)
#define IOCTL_CED_LINECOUNT _IO(CED_MAGIC_IOC, 7)
#define IOCTL_CED_GETSTRING(nMax) _IOC(_IOC_READ, CED_MAGIC_IOC, 8, nMax)
#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, struct transfer_area_desc)
#define IOCTL_CED_UNSETTRANSFER _IO(CED_MAGIC_IOC, 12)
#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, struct transfer_event)
#define IOCTL_CED_GETOUTBUFSPACE _IO(CED_MAGIC_IOC, 14)
#define IOCTL_CED_GETBASEADDRESS _IO(CED_MAGIC_IOC, 15)
#define IOCTL_CED_GETDRIVERREVISION _IO(CED_MAGIC_IOC, 16)
#define IOCTL_CED_GETTRANSFER _IOR(CED_MAGIC_IOC, 17, TGET_TX_BLOCK)
#define IOCTL_CED_KILLIO1401 _IO(CED_MAGIC_IOC, 18)
#define IOCTL_CED_BLKTRANSSTATE _IO(CED_MAGIC_IOC, 19)
#define IOCTL_CED_STATEOF1401 _IO(CED_MAGIC_IOC, 23)
#define IOCTL_CED_GRAB1401 _IO(CED_MAGIC_IOC, 25)
#define IOCTL_CED_FREE1401 _IO(CED_MAGIC_IOC, 26)
#define IOCTL_CED_STARTSELFTEST _IO(CED_MAGIC_IOC, 31)
#define IOCTL_CED_CHECKSELFTEST _IOR(CED_MAGIC_IOC, 32, TGET_SELFTEST)
#define IOCTL_CED_TYPEOF1401 _IO(CED_MAGIC_IOC, 33)
#define IOCTL_CED_TRANSFERFLAGS _IO(CED_MAGIC_IOC, 34)
#define IOCTL_CED_DBGPEEK _IOW(CED_MAGIC_IOC, 35, TDBGBLOCK)
#define IOCTL_CED_DBGPOKE _IOW(CED_MAGIC_IOC, 36, TDBGBLOCK)
#define IOCTL_CED_DBGRAMPDATA _IOW(CED_MAGIC_IOC, 37, TDBGBLOCK)
#define IOCTL_CED_DBGRAMPADDR _IOW(CED_MAGIC_IOC, 38, TDBGBLOCK)
#define IOCTL_CED_DBGGETDATA _IOR(CED_MAGIC_IOC, 39, TDBGBLOCK)
#define IOCTL_CED_DBGSTOPLOOP _IO(CED_MAGIC_IOC, 40)
#define IOCTL_CED_FULLRESET _IO(CED_MAGIC_IOC, 41)
#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, struct transfer_area_desc)
#define IOCTL_CED_GETCIRCBLOCK _IOWR(CED_MAGIC_IOC, 43, TCIRCBLOCK)
#define IOCTL_CED_FREECIRCBLOCK _IOWR(CED_MAGIC_IOC, 44, TCIRCBLOCK)
#define IOCTL_CED_WAITEVENT _IO(CED_MAGIC_IOC, 45)
#define IOCTL_CED_TESTEVENT _IO(CED_MAGIC_IOC, 46)
#ifndef __KERNEL__
/*
* If nothing said about return value, it is a U14ERR_... error code
* (U14ERR_NOERROR for none)
*/
inline int CED_SendString(int fh, const char *szText, int n)
{
return ioctl(fh, IOCTL_CED_SENDSTRING(n), szText);
}
inline int CED_Reset1401(int fh)
{
return ioctl(fh, IOCTL_CED_RESET1401);
}
/* Return the singe character or a -ve error code. */
inline int CED_GetChar(int fh)
{
return ioctl(fh, IOCTL_CED_GETCHAR);
}
/* Return character count in input buffer */
inline int CED_Stat1401(int fh)
{
return ioctl(fh, IOCTL_CED_STAT1401);
}
inline int CED_SendChar(int fh, char c)
{
return ioctl(fh, IOCTL_CED_SENDCHAR, c);
}
inline int CED_LineCount(int fh)
{
return ioctl(fh, IOCTL_CED_LINECOUNT);
}
/*
* return the count of characters returned. If the string was terminated by CR
* or 0, then the 0 is part of the count. Otherwise, we will add a zero if
* there is room, but it is not included in the count. The return value is 0
* if there was nothing to read.
*/
inline int CED_GetString(int fh, char *szText, int nMax)
{
return ioctl(fh, IOCTL_CED_GETSTRING(nMax), szText);
}
/* returns space in the output buffer. */
inline int CED_GetOutBufSpace(int fh)
{
return ioctl(fh, IOCTL_CED_GETOUTBUFSPACE);
}
/* This always returns -1 as not implemented. */
inline int CED_GetBaseAddress(int fh)
{
return ioctl(fh, IOCTL_CED_GETBASEADDRESS);
}
/* returns the major revision <<16 | minor revision. */
inline int CED_GetDriverRevision(int fh)
{
return ioctl(fh, IOCTL_CED_GETDRIVERREVISION);
}
inline int CED_SetTransfer(int fh, struct transfer_area_desc *pTD)
{
return ioctl(fh, IOCTL_CED_SETTRANSFER, pTD);
}
inline int CED_UnsetTransfer(int fh, int nArea)
{
return ioctl(fh, IOCTL_CED_UNSETTRANSFER, nArea);
}
inline int CED_SetEvent(int fh, struct transfer_event *pTE)
{
return ioctl(fh, IOCTL_CED_SETEVENT, pTE);
}
inline int CED_GetTransfer(int fh, TGET_TX_BLOCK *pTX)
{
return ioctl(fh, IOCTL_CED_GETTRANSFER, pTX);
}
inline int CED_KillIO1401(int fh)
{
return ioctl(fh, IOCTL_CED_KILLIO1401);
}
/* returns 0 if no active DMA, 1 if active */
inline int CED_BlkTransState(int fh)
{
return ioctl(fh, IOCTL_CED_BLKTRANSSTATE);
}
inline int CED_StateOf1401(int fh)
{
return ioctl(fh, IOCTL_CED_STATEOF1401);
}
inline int CED_Grab1401(int fh)
{
return ioctl(fh, IOCTL_CED_GRAB1401);
}
inline int CED_Free1401(int fh)
{
return ioctl(fh, IOCTL_CED_FREE1401);
}
inline int CED_StartSelfTest(int fh)
{
return ioctl(fh, IOCTL_CED_STARTSELFTEST);
}
inline int CED_CheckSelfTest(int fh, TGET_SELFTEST *pGST)
{
return ioctl(fh, IOCTL_CED_CHECKSELFTEST, pGST);
}
inline int CED_TypeOf1401(int fh)
{
return ioctl(fh, IOCTL_CED_TYPEOF1401);
}
inline int CED_TransferFlags(int fh)
{
return ioctl(fh, IOCTL_CED_TRANSFERFLAGS);
}
inline int CED_DbgPeek(int fh, TDBGBLOCK *pDB)
{
return ioctl(fh, IOCTL_CED_DBGPEEK, pDB);
}
inline int CED_DbgPoke(int fh, TDBGBLOCK *pDB)
{
return ioctl(fh, IOCTL_CED_DBGPOKE, pDB);
}
inline int CED_DbgRampData(int fh, TDBGBLOCK *pDB)
{
return ioctl(fh, IOCTL_CED_DBGRAMPDATA, pDB);
}
inline int CED_DbgRampAddr(int fh, TDBGBLOCK *pDB)
{
return ioctl(fh, IOCTL_CED_DBGRAMPADDR, pDB);
}
inline int CED_DbgGetData(int fh, TDBGBLOCK *pDB)
{
return ioctl(fh, IOCTL_CED_DBGGETDATA, pDB);
}
inline int CED_DbgStopLoop(int fh)
{
return ioctl(fh, IOCTL_CED_DBGSTOPLOOP);
}
inline int CED_FullReset(int fh)
{
return ioctl(fh, IOCTL_CED_FULLRESET);
}
inline int CED_SetCircular(int fh, struct transfer_area_desc *pTD)
{
return ioctl(fh, IOCTL_CED_SETCIRCULAR, pTD);
}
inline int CED_GetCircBlock(int fh, TCIRCBLOCK *pCB)
{
return ioctl(fh, IOCTL_CED_GETCIRCBLOCK, pCB);
}
inline int CED_FreeCircBlock(int fh, TCIRCBLOCK *pCB)
{
return ioctl(fh, IOCTL_CED_FREECIRCBLOCK, pCB);
}
inline int CED_WaitEvent(int fh, int nArea, int msTimeOut)
{
return ioctl(fh, IOCTL_CED_WAITEVENT, (nArea & 0xff)|(msTimeOut << 8));
}
inline int CED_TestEvent(int fh, int nArea)
{
return ioctl(fh, IOCTL_CED_TESTEVENT, nArea);
}
#endif
#ifdef NOTWANTEDYET
#define IOCTL_CED_REGCALLBACK _IO(CED_MAGIC_IOC, 9) /* Not used */
#define IOCTL_CED_GETMONITORBUF _IO(CED_MAGIC_IOC, 10) /* Not used */
#define IOCTL_CED_BYTECOUNT _IO(CED_MAGIC_IOC, 20) /* Not used */
#define IOCTL_CED_ZEROBLOCKCOUNT _IO(CED_MAGIC_IOC, 21) /* Not used */
#define IOCTL_CED_STOPCIRCULAR _IO(CED_MAGIC_IOC, 22) /* Not used */
#define IOCTL_CED_REGISTERS1401 _IO(CED_MAGIC_IOC, 24) /* Not used */
#define IOCTL_CED_STEP1401 _IO(CED_MAGIC_IOC, 27) /* Not used */
#define IOCTL_CED_SET1401REGISTERS _IO(CED_MAGIC_IOC, 28) /* Not used */
#define IOCTL_CED_STEPTILL1401 _IO(CED_MAGIC_IOC, 29) /* Not used */
#define IOCTL_CED_SETORIN _IO(CED_MAGIC_IOC, 30) /* Not used */
#endif
/* __CED_IOCTL_H__ */
#endif
/*****************************************************************************
**
** machine.h
**
** Copyright (c) Cambridge Electronic Design Limited 1991,1992,2010
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road
** Cambridge, CB6 0FE.
** www.ced.co.uk
** greg@ced.co.uk
**
** This file is included at the start of 'C' or 'C++' source file to define
** things for cross-platform/compiler interoperability. This used to deal with
** MSDOS/16-bit stuff, but this was all removed in Decemeber 2010. There are
** three things to consider: Windows, LINUX, mac OSX (BSD Unix) and 32 vs 64
** bit. At the time of writing (DEC 2010) there is a consensus on the following
** and their unsigned equivalents:
**
** type bits
** char 8
** short 16
** int 32
** long long 64
**
** long is a problem as it is always 64 bits on linux/unix and is always 32 bits
** on windows.
** On windows, we define _IS_WINDOWS_ and one of WIN32 or WIN64.
** On linux we define LINUX
** On Max OSX we define MACOSX
**
*/
#ifndef __MACHINE_H__
#define __MACHINE_H__
#ifndef __KERNEL__
#include <float.h>
#include <limits.h>
#endif
/*
** The initial section is to identify the operating system
*/
#if (defined(__linux__) || defined(_linux) || defined(__linux)) && !defined(LINUX)
#define LINUX 1
#endif
#if (defined(__WIN32__) || defined(_WIN32)) && !defined(WIN32)
#define WIN32 1
#endif
#if defined(__APPLE__)
#define MACOSX
#endif
#if defined(_WIN64)
#undef WIN32
#undef WIN64
#define WIN64 1
#endif
#if defined(WIN32) || defined(WIN64)
#define _IS_WINDOWS_ 1
#endif
#if defined(LINUX) || defined(MAXOSX)
#define FAR
typedef int BOOL; /* To match Windows */
typedef unsigned char BYTE;
#define __packed __attribute__((packed))
#define HIWORD(x) (unsigned short)(((x)>>16) & 0xffff)
#define LOWORD(x) (unsigned short)((x) & 0xffff)
#endif
#ifdef _IS_WINDOWS_
#include <windows.h>
#define __packed
#endif
/*
** Sort out the DllExport and DllImport macros. The GCC compiler has its own
** syntax for this, though it also supports the MS specific __declspec() as
** a synonym.
*/
#ifdef GNUC
#define DllExport __attribute__((dllexport))
#define DllImport __attribute__((dllimport))
#endif
#ifndef DllExport
#ifdef _IS_WINDOWS_
#define DllExport __declspec(dllexport)
#define DllImport __declspec(dllimport)
#else
#define DllExport
#define DllImport
#endif
#endif /* _IS_WINDOWS_ */
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#endif
/*******************************************************************************
CED1401 usb driver. This basic loading is based on the usb-skeleton.c code that
is:
Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
Copyright (C) 2012 Alois Schloegl <alois.schloegl@ist.ac.at>
There is not a great deal of the skeleton left.
All the remainder dealing specifically with the CED1401 is based on drivers
written by CED for other systems (mainly Windows) and is:
Copyright (C) 2010 Cambridge Electronic Design Ltd
Author Greg P Smith (greg@ced.co.uk)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Endpoints
*********
There are 4 endpoints plus the control endpoint in the standard interface
provided by most 1401s. The control endpoint is used for standard USB requests,
plus various CED-specific transactions such as start self test, debug and get
the 1401 status. The other endpoints are:
1 Characters to the 1401
2 Characters from the 1401
3 Block data to the 1401
4 Block data to the host.
inside the driver these are indexed as an array from 0 to 3, transactions
over the control endpoint are carried out using a separate mechanism. The
use of the endpoints is mostly straightforward, with the driver issuing
IO request packets (IRPs) as required to transfer data to and from the 1401.
The handling of endpoint 2 is different because it is used for characters
from the 1401, which can appear spontaneously and without any other driver
activity - for example to repeatedly request DMA transfers in Spike2. The
desired effect is achieved by using an interrupt endpoint which can be
polled to see if it has data available, and writing the driver so that it
always maintains a pending read IRP from that endpoint which will read the
character data and terminate as soon as the 1401 makes data available. This
works very well, some care is taken with when you kick off this character
read IRP to avoid it being active when it is not wanted but generally it
is running all the time.
In the 2270, there are only three endpoints plus the control endpoint. In
addition to the transactions mentioned above, the control endpoint is used
to transfer character data to the 1401. The other endpoints are used as:
1 Characters from the 1401
2 Block data to the 1401
3 Block data to the host.
The type of interface available is specified by the interface subclass field
in the interface descriptor provided by the 1401. See the USB_INT_ constants
for the values that this field can hold.
****************************************************************************
Linux implementation
Although Linux Device Drivers (3rd Edition) was a major source of information,
it is very out of date. A lot of information was gleaned from the latest
usb_skeleton.c code (you need to download the kernel sources to get this).
To match the Windows version, everything is done using ioctl calls. All the
device state is held in the struct ced_data.
Block transfers are done by using get_user_pages() to pin down a list of
pages that we hold a pointer to in the device driver. We also allocate a
coherent transfer buffer of size STAGED_SZ (this must be a multiple of the
bulk endpoint size so that the 1401 does not realise that we break large
transfers down into smaller pieces). We use kmap_atomic() to get a kernel
va for each page, as it is required, for copying; see ced_copy_user_space().
All character and data transfers are done using asynchronous IO. All Urbs are
tracked by anchoring them. Status and debug ioctls are implemented with the
synchronous non-Urb based transfers.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include "usb1401.h"
/* Define these values to match your devices */
#define USB_CED_VENDOR_ID 0x0525
#define USB_CED_PRODUCT_ID 0xa0f0
/* table of devices that work with this driver */
static const struct usb_device_id ced_table[] = {
{USB_DEVICE(USB_CED_VENDOR_ID, USB_CED_PRODUCT_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ced_table);
/* Get a minor range for your devices from the usb maintainer */
#define USB_CED_MINOR_BASE 192
/* our private defines. if this grows any larger, use your own .h file */
#define MAX_TRANSFER (PAGE_SIZE - 512)
/* MAX_TRANSFER is chosen so that the VM is not stressed by
allocations > PAGE_SIZE and the number of packets in a page
is an integer 512 is the largest possible packet on EHCI */
#define WRITES_IN_FLIGHT 8
/* arbitrarily chosen */
static struct usb_driver ced_driver;
static void ced_delete(struct kref *kref)
{
struct ced_data *ced = to_ced_data(kref);
/* Free up the output buffer, then free the output urb. Note that the */
/* interface member of ced will probably be NULL, so cannot be used */
/* to get to dev. */
usb_free_coherent(ced->udev, OUTBUF_SZ, ced->coher_char_out,
ced->urb_char_out->transfer_dma);
usb_free_urb(ced->urb_char_out);
/* Do the same for chan input */
usb_free_coherent(ced->udev, INBUF_SZ, ced->coher_char_in,
ced->urb_char_in->transfer_dma);
usb_free_urb(ced->urb_char_in);
/* Do the same for the block transfers */
usb_free_coherent(ced->udev, STAGED_SZ, ced->coher_staged_io,
ced->staged_urb->transfer_dma);
usb_free_urb(ced->staged_urb);
usb_put_dev(ced->udev);
kfree(ced);
}
/* This is the driver end of the open() call from user space. */
static int ced_open(struct inode *inode, struct file *file)
{
struct ced_data *ced;
int retval = 0;
int subminor = iminor(inode);
struct usb_interface *interface =
usb_find_interface(&ced_driver, subminor);
if (!interface) {
pr_err("%s - error, can't find device for minor %d", __func__,
subminor);
retval = -ENODEV;
goto exit;
}
ced = usb_get_intfdata(interface);
if (!ced) {
retval = -ENODEV;
goto exit;
}
dev_dbg(&interface->dev, "%s: got ced\n", __func__);
/* increment our usage count for the device */
kref_get(&ced->kref);
/* lock the device to allow correctly handling errors
* in resumption */
mutex_lock(&ced->io_mutex);
if (!ced->open_count++) {
retval = usb_autopm_get_interface(interface);
if (retval) {
ced->open_count--;
mutex_unlock(&ced->io_mutex);
kref_put(&ced->kref, ced_delete);
goto exit;
}
} else { /* uncomment this block if you want exclusive open */
dev_err(&interface->dev, "%s: fail: already open\n", __func__);
retval = -EBUSY;
ced->open_count--;
mutex_unlock(&ced->io_mutex);
kref_put(&ced->kref, ced_delete);
goto exit;
}
/* prevent the device from being autosuspended */
/* save our object in the file's private structure */
file->private_data = ced;
mutex_unlock(&ced->io_mutex);
exit:
return retval;
}
static int ced_release(struct inode *inode, struct file *file)
{
struct ced_data *ced = file->private_data;
if (ced == NULL)
return -ENODEV;
dev_dbg(&ced->interface->dev, "%s: called\n", __func__);
mutex_lock(&ced->io_mutex);
if (!--ced->open_count && ced->interface) /* Allow autosuspend */
usb_autopm_put_interface(ced->interface);
mutex_unlock(&ced->io_mutex);
/* decrement the count on our device */
kref_put(&ced->kref, ced_delete);
return 0;
}
static int ced_flush(struct file *file, fl_owner_t id)
{
int res;
struct ced_data *ced = file->private_data;
if (ced == NULL)
return -ENODEV;
dev_dbg(&ced->interface->dev, "%s: char in pend=%d\n",
__func__, ced->read_chars_pending);
/* wait for io to stop */
mutex_lock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: got io_mutex\n", __func__);
ced_draw_down(ced);
/* read out errors, leave subsequent opens a clean slate */
spin_lock_irq(&ced->err_lock);
res = ced->errors ? (ced->errors == -EPIPE ? -EPIPE : -EIO) : 0;
ced->errors = 0;
spin_unlock_irq(&ced->err_lock);
mutex_unlock(&ced->io_mutex);
dev_dbg(&ced->interface->dev, "%s: exit reached\n", __func__);
return res;
}
/***************************************************************************
** can_accept_io_requests
** If the device is removed, interface is set NULL. We also clear our pointer
** from the interface, so we should make sure that ced is not NULL. This will
** not help with a device extension held by a file.
** return true if can accept new io requests, else false
*/
static bool can_accept_io_requests(struct ced_data *ced)
{
return ced && ced->interface; /* Can we accept IO requests */
}
/****************************************************************************
** Callback routine to complete writes. This may need to fire off another
** urb to complete the transfer.
****************************************************************************/
static void ced_writechar_callback(struct urb *urb)
{
struct ced_data *ced = urb->context;
int got = urb->actual_length; /* what we transferred */
if (urb->status) { /* sync/async unlink faults aren't errors */
if (!
(urb->status == -ENOENT || urb->status == -ECONNRESET
|| urb->status == -ESHUTDOWN)) {
dev_err(&ced->interface->dev,
"%s: nonzero write bulk status received: %d\n",
__func__, urb->status);
}
spin_lock(&ced->err_lock);
ced->errors = urb->status;
spin_unlock(&ced->err_lock);
got = 0; /* and tidy up again if so */
spin_lock(&ced->char_out_lock); /* already at irq level */
ced->out_buff_get = 0; /* Reset the output buffer */
ced->out_buff_put = 0;
ced->num_output = 0; /* Clear the char count */
ced->pipe_error[0] = 1; /* Flag an error for later */
ced->send_chars_pending = false; /* Allow other threads again */
spin_unlock(&ced->char_out_lock); /* already at irq level */
dev_dbg(&ced->interface->dev,
"%s: char out done, 0 chars sent\n", __func__);
} else {
dev_dbg(&ced->interface->dev,
"%s: char out done, %d chars sent\n", __func__, got);
spin_lock(&ced->char_out_lock); /* already at irq level */
ced->num_output -= got; /* Now adjust the char send buffer */
ced->out_buff_get += got; /* to match what we did */
/* Can't do this any earlier as data could be overwritten */
if (ced->out_buff_get >= OUTBUF_SZ)
ced->out_buff_get = 0;
if (ced->num_output > 0) { /* if more to be done... */
int pipe = 0; /* The pipe number to use */
int ret;
char *pDat = &ced->output_buffer[ced->out_buff_get];
/* maximum to send */
unsigned int count = ced->num_output;
/* does it cross buffer end? */
if ((ced->out_buff_get + count) > OUTBUF_SZ)
count = OUTBUF_SZ - ced->out_buff_get;
/* we are done with stuff that changes */
spin_unlock(&ced->char_out_lock);
/* copy output data to the buffer */
memcpy(ced->coher_char_out, pDat, count);
usb_fill_bulk_urb(ced->urb_char_out, ced->udev,
usb_sndbulkpipe(ced->udev,
ced->ep_addr[0]),
ced->coher_char_out, count,
ced_writechar_callback, ced);
ced->urb_char_out->transfer_flags |=
URB_NO_TRANSFER_DMA_MAP;
/* in case we need to kill it */
usb_anchor_urb(ced->urb_char_out, &ced->submitted);
ret = usb_submit_urb(ced->urb_char_out, GFP_ATOMIC);
dev_dbg(&ced->interface->dev, "%s: n=%d>%s<\n",
__func__, count, pDat);
/* grab lock for errors */
spin_lock(&ced->char_out_lock);
if (ret) {
/* Flag an error to be handled later */
ced->pipe_error[pipe] = 1;
/* Allow other threads again */
ced->send_chars_pending = false;
usb_unanchor_urb(ced->urb_char_out);
dev_err(&ced->interface->dev,
"%s: usb_submit_urb() returned %d\n",
__func__, ret);
}
} else
/* Allow other threads again */
ced->send_chars_pending = false;
spin_unlock(&ced->char_out_lock); /* already at irq level */
}
}
/****************************************************************************
** ced_send_chars
** Transmit the characters in the output buffer to the 1401. This may need
** breaking down into multiple transfers.
****************************************************************************/
int ced_send_chars(struct ced_data *ced)
{
int retval = U14ERR_NOERROR;
spin_lock_irq(&ced->char_out_lock); /* Protect ourselves */
if ((!ced->send_chars_pending) && /* Not currently sending */
(ced->num_output > 0) && /* has characters to output */
(can_accept_io_requests(ced))) { /* and current activity is OK */
unsigned int count = ced->num_output; /* Get a copy of the */
/* character count */
/* Set flag to lock out other threads */
ced->send_chars_pending = true;
dev_dbg(&ced->interface->dev,
"Send %d chars to 1401, EP0 flag %d\n",
count, ced->n_pipes == 3);
/* If we have only 3 end points we must send the characters */
/* to the 1401 using EP0. */
if (ced->n_pipes == 3) {
/* For EP0 character transmissions to the 1401, we */
/* have to hang about until they are gone, as */
/* otherwise without more character IO activity */
/* they will never go. */
unsigned int i = count; /* Local char counter */
unsigned int index = 0; /* The index into the */
/* char buffer */
/* Free spinlock as we call USBD */
spin_unlock_irq(&ced->char_out_lock);
while ((i > 0) && (retval == U14ERR_NOERROR)) {
/* We have to break the transfer up into 64-byte chunks because of a 2270 problem */
int n = i > 64 ? 64 : i; /* Chars for this xfer, max of 64 */
int sent = usb_control_msg(ced->udev,
usb_sndctrlpipe(ced->udev, 0), /* use end point 0 */
DB_CHARS, /* bRequest */
(H_TO_D | VENDOR | DEVREQ), /* to the device, vendor request to the device */
0, 0, /* value and index are both 0 */
&ced->output_buffer[index], /* where to send from */
n, /* how much to send */
1000); /* timeout in jiffies */
if (sent <= 0) {
/* if 0 chars says we timed out */
retval = sent ? sent : -ETIMEDOUT;
dev_err(&ced->interface->dev,
"Send %d chars by EP0 failed: %d\n",
n, retval);
} else {
dev_dbg(&ced->interface->dev,
"Sent %d chars by EP0\n", n);
i -= sent;
index += sent;
}
}
/* Protect ced changes, released by general code */
spin_lock_irq(&ced->char_out_lock);
ced->out_buff_get = 0; /* so reset the output buffer */
ced->out_buff_put = 0;
ced->num_output = 0; /* and clear the buffer count */
/* Allow other threads again */
ced->send_chars_pending = false;
} else { /* Here for sending chars normally - we hold the */
/* spin lock */
int pipe = 0; /* The pipe number to use */
char *pDat = &ced->output_buffer[ced->out_buff_get];
/* does it cross buffer end? */
if ((ced->out_buff_get + count) > OUTBUF_SZ)
count = OUTBUF_SZ - ced->out_buff_get;
/* we are done with stuff that changes */
spin_unlock_irq(&ced->char_out_lock);
/* copy output data to the buffer */
memcpy(ced->coher_char_out, pDat, count);
usb_fill_bulk_urb(ced->urb_char_out, ced->udev,
usb_sndbulkpipe(ced->udev,
ced->ep_addr[0]),
ced->coher_char_out, count,
ced_writechar_callback, ced);
ced->urb_char_out->transfer_flags |=
URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(ced->urb_char_out, &ced->submitted);
retval = usb_submit_urb(ced->urb_char_out, GFP_KERNEL);
/* grab lock for errors */
spin_lock_irq(&ced->char_out_lock);
if (retval) {
/* Flag an error to be handled later */
ced->pipe_error[pipe] = 1;
/* Allow other threads again */
ced->send_chars_pending = false;
/* remove from list of active urbs */
usb_unanchor_urb(ced->urb_char_out);
}
}
} else if (ced->send_chars_pending && (ced->num_output > 0))
dev_dbg(&ced->interface->dev,
"%s: send_chars_pending:true\n", __func__);
dev_dbg(&ced->interface->dev, "%s: exit code: %d\n", __func__, retval);
spin_unlock_irq(&ced->char_out_lock); /* Now let go of the spinlock */
return retval;
}
/***************************************************************************
** ced_copy_user_space
** This moves memory between pinned down user space and the coher_staged_io
** memory buffer we use for transfers. Copy n bytes in the directions that
** is defined by ced->staged_read. The user space is determined by the area
** in ced->staged_id and the offset in ced->staged_done. The user
** area may well not start on a page boundary, so allow for that.
**
** We have a table of physical pages that describe the area, so we can use
** this to get a virtual address that the kernel can use.
**
** ced Is our device extension which holds all we know about the transfer.
** n The number of bytes to move one way or the other.
***************************************************************************/
static void ced_copy_user_space(struct ced_data *ced, int n)
{
unsigned int area = ced->staged_id;
if (area < MAX_TRANSAREAS) {
/* area to be used */
struct transarea *ta = &ced->trans_def[area];
unsigned int offset =
ced->staged_done + ced->staged_offset + ta->base_offset;
char *coher_buf = ced->coher_staged_io; /* coherent buffer */
if (!ta->used) {
dev_err(&ced->interface->dev, "%s: area %d unused\n",
__func__, area);
return;
}
while (n) {
/* page number in table */
int page = offset >> PAGE_SHIFT;
if (page < ta->n_pages) {
char *address =
(char *)kmap_atomic(ta->pages[page]);
if (address) {
/* offset into the page */
unsigned int page_off =
offset & (PAGE_SIZE - 1);
/* max to transfer on this page */
size_t xfer = PAGE_SIZE - page_off;
/* limit byte count if too much */
/* for the page */
if (xfer > n)
xfer = n;
if (ced->staged_read)
memcpy(address + page_off,
coher_buf, xfer);
else
memcpy(coher_buf,
address + page_off,
xfer);
kunmap_atomic(address);
offset += xfer;
coher_buf += xfer;
n -= xfer;
} else {
dev_err(&ced->interface->dev,
"%s: did not map page %d\n",
__func__, page);
return;
}
} else {
dev_err(&ced->interface->dev,
"%s: exceeded pages %d\n",
__func__, page);
return;
}
}
} else
dev_err(&ced->interface->dev, "%s: bad area %d\n",
__func__, area);
}
/* Forward declarations for stuff used circularly */
static int ced_stage_chunk(struct ced_data *ced);
/***************************************************************************
** ReadWrite_Complete
**
** Completion routine for our staged read/write Irps
*/
static void staged_callback(struct urb *urb)
{
struct ced_data *ced = urb->context;
unsigned int got = urb->actual_length; /* what we transferred */
bool cancel = false;
bool restart_char_input; /* used at the end */
spin_lock(&ced->staged_lock); /* stop ced_read_write_mem() action */
/* while this routine is running */
/* clear the flag for staged IRP pending */
ced->staged_urb_pending = false;
if (urb->status) { /* sync/async unlink faults aren't errors */
if (!
(urb->status == -ENOENT || urb->status == -ECONNRESET
|| urb->status == -ESHUTDOWN)) {
dev_err(&ced->interface->dev,
"%s: nonzero write bulk status received: %d\n",
__func__, urb->status);
} else
dev_info(&ced->interface->dev,
"%s: staged xfer cancelled\n", __func__);
spin_lock(&ced->err_lock);
ced->errors = urb->status;
spin_unlock(&ced->err_lock);
got = 0; /* and tidy up again if so */
cancel = true;
} else {
dev_dbg(&ced->interface->dev, "%s: %d chars xferred\n",
__func__, got);
if (ced->staged_read) /* if reading, save to user space */
/* copy from buffer to user */
ced_copy_user_space(ced, got);
if (got == 0)
dev_dbg(&ced->interface->dev, "%s: ZLP\n", __func__);
}
/* Update the transfer length based on the TransferBufferLength value */
/* in the URB */
ced->staged_done += got;
dev_dbg(&ced->interface->dev, "%s: done %d bytes of %d\n",
__func__, ced->staged_done, ced->staged_length);
if ((ced->staged_done == ced->staged_length) || /* If no more to do */
(cancel)) { /* or this IRP was cancelled */
/* Transfer area info */
struct transarea *ta = &ced->trans_def[ced->staged_id];
dev_dbg(&ced->interface->dev,
"%s: transfer done, bytes %d, cancel %d\n",
__func__, ced->staged_done, cancel);
/* Here is where we sort out what to do with this transfer if */
/* using a circular buffer. We have a completed transfer that */
/* can be assumed to fit into the transfer area. We should be */
/* able to add this to the end of a growing block or to use */
/* it to start a new block unless the code that calculates */
/* the offset to use (in ced_read_write_mem) is totally duff. */
if ((ta->circular) &&
(ta->circ_to_host) &&
(!cancel) && /* Time to sort out circular buffer info? */
(ced->staged_read)) {/* Only for tohost transfers for now */
/* If block 1 is in use we must append to it */
if (ta->blocks[1].size > 0) {
if (ced->staged_offset ==
(ta->blocks[1].offset +
ta->blocks[1].size)) {
ta->blocks[1].size +=
ced->staged_length;
dev_dbg(&ced->interface->dev,
"RWM_Complete, circ block 1 now %d bytes at %d\n",
ta->blocks[1].size,
ta->blocks[1].offset);
} else {
/* Here things have gone very, very */
/* wrong, but I cannot see how this */
/* can actually be achieved */
ta->blocks[1].offset =
ced->staged_offset;
ta->blocks[1].size =
ced->staged_length;
dev_err(&ced->interface->dev,
"%s: ERROR, circ block 1 re-started %d bytes at %d\n",
__func__,
ta->blocks[1].size,
ta->blocks[1].offset);
}
} else { /* If block 1 is not used, we try to add */
/*to block 0 */
/* Got stored block 0 information? */
if (ta->blocks[0].size > 0) {
/* Must append onto the */
/*existing block 0 */
if (ced->staged_offset ==
(ta->blocks[0].offset +
ta->blocks[0].size)) {
/* Just add this transfer in */
ta->blocks[0].size +=
ced->staged_length;
dev_dbg(&ced->interface->dev,
"RWM_Complete, circ block 0 now %d bytes at %d\n",
ta->blocks[0].size,
ta->blocks[0].offset);
} else { /* If it doesn't append, put */
/* into new block 1 */
ta->blocks[1].offset =
ced->staged_offset;
ta->blocks[1].size =
ced->staged_length;
dev_dbg(&ced->interface->dev,
"RWM_Complete, circ block 1 started %d bytes at %d\n",
ta->blocks[1].size,
ta->blocks[1].offset);
}
} else { /* No info stored yet, just save */
/* in block 0 */
ta->blocks[0].offset =
ced->staged_offset;
ta->blocks[0].size =
ced->staged_length;
dev_dbg(&ced->interface->dev,
"RWM_Complete, circ block 0 started %d bytes at %d\n",
ta->blocks[0].size,
ta->blocks[0].offset);
}
}
}
if (!cancel) { /* Don't generate an event if cancelled */
dev_dbg(&ced->interface->dev,
"RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d\n",
ta->circular, ta->event_to_host,
ta->event_st, ta->event_sz);
/* Set a user-mode event... */
/* ...on transfers in this direction? */
if ((ta->event_sz) &&
(ced->staged_read == ta->event_to_host)) {
int wakeup = 0; /* assume */
/* If we have completed the right sort of DMA */
/* transfer then set the event to notify the */
/* user code to wake up anyone that is */
/* waiting. */
if ((ta->circular) && /* Circular areas use a
simpler test */
(ta->circ_to_host)) { /* only in supported
direction */
/* Is total data waiting up */
/* to size limit? */
unsigned int dwTotal =
ta->blocks[0].size +
ta->blocks[1].size;
wakeup = (dwTotal >= ta->event_sz);
} else {
unsigned int transEnd =
ced->staged_offset +
ced->staged_length;
unsigned int eventEnd =
ta->event_st + ta->event_sz;
wakeup = (ced->staged_offset < eventEnd)
&& (transEnd > ta->event_st);
}
if (wakeup) {
dev_dbg(&ced->interface->dev,
"About to set event to notify app\n");
/* wake up waiting processes */
wake_up_interruptible(&ta->event);
/* increment wakeup count */
++ta->wake_up;
}
}
}
/* Switch back to char mode before ced_read_write_mem call */
ced->dma_flag = MODE_CHAR;
/* Don't look for waiting transfer if cancelled */
if (!cancel) {
/* If we have a transfer waiting, kick it off */
if (ced->xfer_waiting) {/* Got a block xfer waiting? */
int retval;
dev_info(&ced->interface->dev,
"*** RWM_Complete *** pending transfer will now be set up!!!\n");
retval =
ced_read_write_mem(ced,
!ced->dma_info.outward,
ced->dma_info.ident,
ced->dma_info.offset,
ced->dma_info.size);
if (retval)
dev_err(&ced->interface->dev,
"RWM_Complete rw setup failed %d\n",
retval);
}
}
} else /* Here for more to do */
ced_stage_chunk(ced); /* fire off the next bit */
/* While we hold the staged_lock, see if we should reallow character */
/* input ints */
/* Don't allow if cancelled, or if a new block has started or if */
/* there is a waiting block. */
/* This feels wrong as we should ask which spin lock protects */
/* dma_flag. */
restart_char_input = !cancel && (ced->dma_flag == MODE_CHAR) &&
!ced->xfer_waiting;
spin_unlock(&ced->staged_lock); /* Finally release the lock again */
/* This is not correct as dma_flag is protected by the staged lock, */
/* but it is treated in ced_allowi as if it were protected by the */
/* char lock. In any case, most systems will not be upset by char */
/* input during DMA... sigh. Needs sorting out. */
if (restart_char_input) /* may be out of date, but... */
ced_allowi(ced); /* ...ced_allowi tests a lock too. */
dev_dbg(&ced->interface->dev, "%s: done\n", __func__);
}
/****************************************************************************
** ced_stage_chunk
**
** Generates the next chunk of data making up a staged transfer.
**
** The calling code must have acquired the staging spinlock before calling
** this function, and is responsible for releasing it. We are at callback level.
****************************************************************************/
static int ced_stage_chunk(struct ced_data *ced)
{
int retval = U14ERR_NOERROR;
unsigned int chunk_size;
int pipe = ced->staged_read ? 3 : 2; /* The pipe number to use for */
/* reads or writes */
if (ced->n_pipes == 3)
pipe--; /* Adjust for the 3-pipe case */
if (pipe < 0) /* and trap case that should never happen */
return U14ERR_FAIL;
if (!can_accept_io_requests(ced)) { /* got sudden remove? */
dev_info(&ced->interface->dev, "%s: sudden remove, giving up\n",
__func__);
return U14ERR_FAIL; /* could do with a better error */
}
/* transfer length remaining */
chunk_size = (ced->staged_length - ced->staged_done);
if (chunk_size > STAGED_SZ) /* make sure to keep legal */
chunk_size = STAGED_SZ; /* limit to max allowed */
if (!ced->staged_read) /* if writing... */
/* ...copy data into the buffer */
ced_copy_user_space(ced, chunk_size);
usb_fill_bulk_urb(ced->staged_urb, ced->udev,
ced->staged_read ? usb_rcvbulkpipe(ced->udev,
ced->
ep_addr[pipe]) :
usb_sndbulkpipe(ced->udev, ced->ep_addr[pipe]),
ced->coher_staged_io, chunk_size,
staged_callback, ced);
ced->staged_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* in case we need to kill it */
usb_anchor_urb(ced->staged_urb, &ced->submitted);
retval = usb_submit_urb(ced->staged_urb, GFP_ATOMIC);
if (retval) {
usb_unanchor_urb(ced->staged_urb); /* kill it */
ced->pipe_error[pipe] = 1; /* Flag an error to be */
/* handled later */
dev_err(&ced->interface->dev,
"%s: submit urb failed, code %d\n",
__func__, retval);
} else
/* Set the flag for staged URB pending */
ced->staged_urb_pending = true;
dev_dbg(&ced->interface->dev, "%s: done so far:%d, this size:%d\n",
__func__, ced->staged_done, chunk_size);
return retval;
}
/***************************************************************************
** ced_read_write_mem
**
** This routine is used generally for block read and write operations.
** Breaks up a read or write in to specified sized chunks, as specified by pipe
** information on maximum transfer size.
**
** Any code that calls this must be holding the staged_lock
**
** Arguments:
** DeviceObject - pointer to our FDO (Functional Device Object)
** read - TRUE for read, FALSE for write. This is from POV of the driver
** ident - the transfer area number - defines memory area and more.
** offs - the start offset within the transfer area of the start of this
** transfer.
** len - the number of bytes to transfer.
*/
int ced_read_write_mem(struct ced_data *ced, bool read, unsigned short ident,
unsigned int offs, unsigned int len)
{
/* Transfer area info */
struct transarea *ta = &ced->trans_def[ident];
/* Are we in a state to accept new requests? */
if (!can_accept_io_requests(ced)) {
dev_err(&ced->interface->dev, "%s: can't accept requests\n",
__func__);
return U14ERR_FAIL;
}
dev_dbg(&ced->interface->dev,
"%s: xfer %d bytes to %s, offset %d, area %d\n",
__func__, len, read ? "host" : "1401", offs, ident);
/* Amazingly, we can get an escape sequence back before the current */
/* staged Urb is done, so we have to check for this situation and, if */
/* so, wait until all is OK. */
if (ced->staged_urb_pending) {
ced->xfer_waiting = true; /* Flag we are waiting */
dev_info(&ced->interface->dev,
"%s: xfer is waiting, as previous staged pending\n",
__func__);
return U14ERR_NOERROR;
}
if (len == 0) { /* allow 0-len read or write; just return success */
dev_dbg(&ced->interface->dev,
"%s: OK; zero-len read/write request\n", __func__);
return U14ERR_NOERROR;
}
if ((ta->circular) && /* Circular transfer? */
(ta->circ_to_host) && (read)) { /* In a supported direction */
/* If so, we sort out offset ourself */
bool bWait = false; /* Flag for transfer having to wait */
dev_dbg(&ced->interface->dev,
"Circular buffers are %d at %d and %d at %d\n",
ta->blocks[0].size, ta->blocks[0].offset,
ta->blocks[1].size, ta->blocks[1].offset);
/* Using the second block already? */
if (ta->blocks[1].size > 0) {
/* take offset from that */
offs = ta->blocks[1].offset + ta->blocks[1].size;
/* Wait if will overwrite block 0? */
bWait = (offs + len) > ta->blocks[0].offset;
/* or if it overflows the buffer */
bWait |= (offs + len) > ta->length;
} else { /* Area 1 not in use, try to use area 0 */
/* Reset block 0 if not in use */
if (ta->blocks[0].size == 0)
ta->blocks[0].offset = 0;
offs =
ta->blocks[0].offset +
ta->blocks[0].size;
/* Off the end of the buffer? */
if ((offs + len) > ta->length) {
/* Set up to use second block */
ta->blocks[1].offset = 0;
offs = 0;
/* Wait if will overwrite block 0? */
bWait = (offs + len) > ta->blocks[0].offset;
/* or if it overflows the buffer */
bWait |= (offs + len) > ta->length;
}
}
if (bWait) { /* This transfer will have to wait? */
ced->xfer_waiting = true; /* Flag we are waiting */
dev_dbg(&ced->interface->dev,
"%s: xfer waiting for circular buffer space\n",
__func__);
return U14ERR_NOERROR;
}
dev_dbg(&ced->interface->dev,
"%s: circular xfer, %d bytes starting at %d\n",
__func__, len, offs);
}
/* Save the parameters for the read\write transfer */
ced->staged_read = read; /* Save the parameters for this read */
ced->staged_id = ident; /* ID allows us to get transfer area info */
ced->staged_offset = offs; /* The area within the transfer area */
ced->staged_length = len;
ced->staged_done = 0; /* Initialise the byte count */
ced->dma_flag = MODE_LINEAR; /* Set DMA mode flag at this point */
ced->xfer_waiting = false; /* Clearly not a transfer waiting now */
/* KeClearEvent(&ced->StagingDoneEvent); // Clear the transfer done event */
ced_stage_chunk(ced); /* fire off the first chunk */
return U14ERR_NOERROR;
}
/****************************************************************************
**
** ced_read_char
**
** Reads a character a buffer. If there is no more
** data we return FALSE. Used as part of decoding a DMA request.
**
****************************************************************************/
static bool ced_read_char(unsigned char *character, char *buf,
unsigned int *n_done, unsigned int got)
{
bool read = false;
unsigned int done = *n_done;
if (done < got) { /* If there is more data */
/* Extract the next char */
*character = (unsigned char)buf[done];
done++; /* Increment the done count */
*n_done = done;
read = true; /* and flag success */
}
return read;
}
#ifdef NOTUSED
/****************************************************************************
**
** ced_read_word
**
** Reads a word from the 1401, just uses ced_read_char twice;
** passes on any error
**
*****************************************************************************/
static bool ced_read_word(unsigned short *word, char *buf, unsigned int *n_done,
unsigned int got)
{
if (ced_read_char((unsigned char *)word, buf, n_done, got))
return ced_read_char(((unsigned char *)word) + 1, buf, n_done,
got);
else
return false;
}
#endif
/****************************************************************************
** ced_read_huff
**
** Reads a coded number in and returns it, Code is:
** If data is in range 0..127 we receive 1 byte. If data in range 128-16383
** we receive two bytes, top bit of first indicates another on its way. If
** data in range 16384-4194303 we get three bytes, top two bits of first set
** to indicate three byte total.
**
*****************************************************************************/
static bool ced_read_huff(volatile unsigned int *word, char *buf,
unsigned int *n_done, unsigned int got)
{
unsigned char c; /* for each read to ced_read_char */
bool retval = true; /* assume we will succeed */
unsigned int data = 0; /* Accumulator for the data */
if (ced_read_char(&c, buf, n_done, got)) {
data = c; /* copy the data */
if ((data & 0x00000080) != 0) { /* Bit set for more data ? */
data &= 0x0000007F; /* Clear the relevant bit */
if (ced_read_char(&c, buf, n_done, got)) {
data = (data << 8) | c;
/* three byte sequence ? */
if ((data & 0x00004000) != 0) {
/* Clear the relevant bit */
data &= 0x00003FFF;
if (ced_read_char
(&c, buf, n_done, got))
data = (data << 8) | c;
else
retval = false;
}
} else
retval = false; /* couldn't read data */
}
} else
retval = false;
*word = data; /* return the data */
return retval;
}
/***************************************************************************
**
** ced_read_dma_info
**
** Tries to read info about the dma request from the 1401 and decode it into
** the dma descriptor block. We have at this point had the escape character
** from the 1401 and now we must read in the rest of the information about
** the transfer request. Returns FALSE if 1401 fails to respond or obselete
** code from 1401 or bad parameters.
**
** The buf char pointer does not include the initial escape character, so
** we start handling the data at offset zero.
**
*****************************************************************************/
static bool ced_read_dma_info(volatile struct dmadesc *dma_desc,
struct ced_data *ced,
char *buf, unsigned int count)
{
bool retval = false; /* assume we won't succeed */
unsigned char c;
unsigned int n_done = 0; /* We haven't parsed anything so far */
dev_dbg(&ced->interface->dev, "%s\n", __func__);
if (ced_read_char(&c, buf, &n_done, count)) {
/* get code for transfer type */
unsigned char trans_code = (c & 0x0F);
/* and area identifier */
unsigned short ident = ((c >> 4) & 0x07);
/* fill in the structure we were given */
dma_desc->trans_type = trans_code; /* type of transfer */
dma_desc->ident = ident; /* area to use */
dma_desc->size = 0; /* initialise other bits */
dma_desc->offset = 0;
dev_dbg(&ced->interface->dev, "%s: type: %d ident: %d\n",
__func__, dma_desc->trans_type, dma_desc->ident);
/* set transfer direction */
dma_desc->outward = (trans_code != TM_EXTTOHOST);
switch (trans_code) {
/* Extended linear transfer modes (the only ones!) */
case TM_EXTTOHOST:
case TM_EXTTO1401:
{
retval =
ced_read_huff(&(dma_desc->offset), buf,
&n_done, count)
&& ced_read_huff(&(dma_desc->size), buf,
&n_done, count);
if (retval) {
dev_dbg(&ced->interface->dev,
"%s: xfer offset & size %d %d\n",
__func__, dma_desc->offset,
dma_desc->size);
if ((ident >= MAX_TRANSAREAS) || /* Illegal area number, or... */
(!ced->trans_def[ident].used) || /* area not set up, or... */
(dma_desc->offset > ced->trans_def[ident].length) || /* range/size */
((dma_desc->offset +
dma_desc->size) >
(ced->trans_def[ident].length))) {
/* bad parameter(s) */
retval = false;
dev_dbg(&ced->interface->dev,
"%s: bad param - id %d, bUsed %d, offset %d, size %d, area length %d\n",
__func__, ident,
ced->trans_def[ident].
used,
dma_desc->offset,
dma_desc->size,
ced->trans_def[ident].
length);
}
}
break;
}
default:
break;
}
} else
retval = false;
if (!retval) /* now check parameters for validity */
dev_err(&ced->interface->dev,
"%s: error reading Esc sequence\n",
__func__);
return retval;
}
/****************************************************************************
**
** ced_handle_esc
**
** Deals with an escape sequence coming from the 1401. This can either be
** a DMA transfer request of various types or a response to an escape sequence
** sent to the 1401. This is called from a callback.
**
** Parameters are
**
** count - the number of characters in the device extension char in buffer,
** this is known to be at least 2 or we will not be called.
**
****************************************************************************/
static int ced_handle_esc(struct ced_data *ced, char *ch,
unsigned int count)
{
int retval = U14ERR_FAIL;
/* I have no idea what this next test is about. '?' is 0x3f, which is */
/* area 3, code 15. At the moment, this is not used, so it does no */
/* harm, but unless someone can tell me what this is for, it should */
/* be removed from this and the Windows driver. */
if (ch[0] == '?') { /* Is this an information response */
/* Parse and save the information */
} else {
spin_lock(&ced->staged_lock); /* Lock others out */
/* Get DMA parameters */
if (ced_read_dma_info(&ced->dma_info, ced, ch, count)) {
/* check transfer type */
unsigned short trans_type = ced->dma_info.trans_type;
dev_dbg(&ced->interface->dev,
"%s: xfer to %s, offset %d, length %d\n",
__func__,
ced->dma_info.outward ? "1401" : "host",
ced->dma_info.offset, ced->dma_info.size);
/* Check here for badly out of kilter... */
if (ced->xfer_waiting) {
/* This can never happen, really */
dev_err(&ced->interface->dev,
"ERROR: DMA setup while transfer still waiting\n");
} else {
if ((trans_type == TM_EXTTOHOST)
|| (trans_type == TM_EXTTO1401)) {
retval =
ced_read_write_mem(ced,
!ced->dma_info.outward,
ced->dma_info.ident,
ced->dma_info.offset,
ced->dma_info.size);
if (retval != U14ERR_NOERROR)
dev_err(&ced->interface->dev,
"%s: ced_read_write_mem() failed %d\n",
__func__, retval);
} else /* This covers non-linear
transfer setup */
dev_err(&ced->interface->dev,
"%s: Unknown block xfer type %d\n",
__func__, trans_type);
}
} else /* Failed to read parameters */
dev_err(&ced->interface->dev, "%s: ced_read_dma_info() fail\n",
__func__);
spin_unlock(&ced->staged_lock); /* OK here */
}
dev_dbg(&ced->interface->dev, "%s: returns %d\n", __func__, retval);
return retval;
}
/****************************************************************************
** Callback for the character read complete or error
****************************************************************************/
static void ced_readchar_callback(struct urb *urb)
{
struct ced_data *ced = urb->context;
int got = urb->actual_length; /* what we transferred */
if (urb->status) { /* Do we have a problem to handle? */
/* The pipe number to use for error */
int pipe = ced->n_pipes == 4 ? 1 : 0;
/* sync/async unlink faults aren't errors... */
/* just saying device removed or stopped */
if (!
(urb->status == -ENOENT || urb->status == -ECONNRESET
|| urb->status == -ESHUTDOWN)) {
dev_err(&ced->interface->dev,
"%s: nonzero write bulk status received: %d\n",
__func__, urb->status);
} else
dev_dbg(&ced->interface->dev,
"%s: 0 chars urb->status=%d (shutdown?)\n",
__func__, urb->status);
spin_lock(&ced->err_lock);
ced->errors = urb->status;
spin_unlock(&ced->err_lock);
got = 0; /* and tidy up again if so */
spin_lock(&ced->char_in_lock); /* already at irq level */
ced->pipe_error[pipe] = 1; /* Flag an error for later */
} else {
/* Esc sequence? */
if ((got > 1) && ((ced->coher_char_in[0] & 0x7f) == 0x1b)) {
/* handle it */
ced_handle_esc(ced, &ced->coher_char_in[1], got - 1);
/* already at irq level */
spin_lock(&ced->char_in_lock);
} else {
/* already at irq level */
spin_lock(&ced->char_in_lock);
if (got > 0) {
unsigned int i;
if (got < INBUF_SZ) {
/* tidy the string */
ced->coher_char_in[got] = 0;
dev_dbg(&ced->interface->dev,
"%s: got %d chars >%s<\n",
__func__, got,
ced->coher_char_in);
}
/* We know that whatever we read must fit */
/* in the input buffer */
for (i = 0; i < got; i++) {
ced->input_buffer[ced->in_buff_put++] =
ced->coher_char_in[i] & 0x7F;
if (ced->in_buff_put >= INBUF_SZ)
ced->in_buff_put = 0;
}
if ((ced->num_input + got) <= INBUF_SZ)
/* Adjust the buffer count */
/* accordingly */
ced->num_input += got;
} else
dev_dbg(&ced->interface->dev, "%s: read ZLP\n",
__func__);
}
}
ced->read_chars_pending = false; /* No longer have a pending read */
spin_unlock(&ced->char_in_lock); /* already at irq level */
ced_allowi(ced); /* see if we can do the next one */
}
/****************************************************************************
** ced_allowi
**
** This is used to make sure that there is always a pending input transfer so
** we can pick up any inward transfers. This can be called in multiple contexts
** so we use the irqsave version of the spinlock.
****************************************************************************/
int ced_allowi(struct ced_data *ced)
{
int retval = U14ERR_NOERROR;
unsigned long flags;
/* can be called in multiple contexts */
spin_lock_irqsave(&ced->char_in_lock, flags);
/* We don't want char input running while DMA is in progress as we */
/* know that this can cause sequencing problems for the 2270. So */
/* don't. It will also allow the ERR response to get back to the host */
/* code too early on some PCs, even if there is no actual driver */
/* failure, so we don't allow this at all. */
if (!ced->in_draw_down && /* stop input if */
!ced->read_chars_pending && /* If no read request outstanding */
(ced->num_input < (INBUF_SZ / 2)) && /* and there is some space */
(ced->dma_flag == MODE_CHAR) && /* not doing any DMA */
(!ced->xfer_waiting) && /* no xfer waiting to start */
(can_accept_io_requests(ced))) { /* and activity is generally OK */
/* then off we go */
/* max we could read */
unsigned int max = INBUF_SZ - ced->num_input;
/* The pipe number to use */
int pipe = ced->n_pipes == 4 ? 1 : 0;
dev_dbg(&ced->interface->dev, "%s: %d chars in input buffer\n",
__func__, ced->num_input);
usb_fill_int_urb(ced->urb_char_in, ced->udev,
usb_rcvintpipe(ced->udev, ced->ep_addr[pipe]),
ced->coher_char_in, max, ced_readchar_callback,
ced, ced->interval);
/* short xfers are OK by default */
ced->urb_char_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* in case we need to kill it */
usb_anchor_urb(ced->urb_char_in, &ced->submitted);
retval = usb_submit_urb(ced->urb_char_in, GFP_ATOMIC);
if (retval) {
/* remove from list of active Urbs */
usb_unanchor_urb(ced->urb_char_in);
/* Flag an error to be handled later */
ced->pipe_error[pipe] = 1;
dev_err(&ced->interface->dev,
"%s: submit urb failed: %d\n",
__func__, retval);
} else
/* Flag that we are active here */
ced->read_chars_pending = true;
}
spin_unlock_irqrestore(&ced->char_in_lock, flags);
return retval;
}
/*****************************************************************************
** The ioctl entry point to the driver that is used by us to talk to it.
** inode The device node (no longer in 3.0.0 kernels)
** file The file that is open, which holds our ced pointer
** arg The argument passed in. Note that long is 64-bits in 64-bit system,
** i.e. it is big enough for a 64-bit pointer.
*****************************************************************************/
static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err = 0;
struct ced_data *ced = file->private_data;
if (!can_accept_io_requests(ced)) /* check we still exist */
return -ENODEV;
/* Check that access is allowed, where is is needed. Anything that */
/* would have an indeterminate size will be checked by the */
/* specific command. */
if (_IOC_DIR(cmd) & _IOC_READ) /* read from point of view of user... */
/* is kernel write */
err = !access_ok(VERIFY_WRITE,
(void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE) /* and write from point of */
/* view of user... */
/* is kernel read */
err = !access_ok(VERIFY_READ,
(void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
switch (_IOC_NR(cmd)) {
case _IOC_NR(IOCTL_CED_SENDSTRING(0)):
return ced_send_string(ced, (const char __user *)arg,
_IOC_SIZE(cmd));
case _IOC_NR(IOCTL_CED_RESET1401):
return ced_reset(ced);
case _IOC_NR(IOCTL_CED_GETCHAR):
return ced_get_char(ced);
case _IOC_NR(IOCTL_CED_SENDCHAR):
return ced_send_char(ced, (char)arg);
case _IOC_NR(IOCTL_CED_STAT1401):
return ced_stat_1401(ced);
case _IOC_NR(IOCTL_CED_LINECOUNT):
return ced_line_count(ced);
case _IOC_NR(IOCTL_CED_GETSTRING(0)):
return ced_get_string(ced, (char __user *)arg, _IOC_SIZE(cmd));
case _IOC_NR(IOCTL_CED_SETTRANSFER):
return ced_set_transfer(ced,
(struct transfer_area_desc __user *) arg);
case _IOC_NR(IOCTL_CED_UNSETTRANSFER):
return ced_unset_transfer(ced, (int)arg);
case _IOC_NR(IOCTL_CED_SETEVENT):
return ced_set_event(ced,
(struct transfer_event __user *) arg);
case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE):
return ced_get_out_buf_space(ced);
case _IOC_NR(IOCTL_CED_GETBASEADDRESS):
return -1;
case _IOC_NR(IOCTL_CED_GETDRIVERREVISION):
/* USB | MAJOR | MINOR */
return (2 << 24) | (DRIVERMAJREV << 16) | DRIVERMINREV;
case _IOC_NR(IOCTL_CED_GETTRANSFER):
return ced_get_transfer(ced, (TGET_TX_BLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_KILLIO1401):
return ced_kill_io(ced);
case _IOC_NR(IOCTL_CED_STATEOF1401):
return ced_state_of_1401(ced);
case _IOC_NR(IOCTL_CED_GRAB1401):
case _IOC_NR(IOCTL_CED_FREE1401):
return U14ERR_NOERROR;
case _IOC_NR(IOCTL_CED_STARTSELFTEST):
return ced_start_self_test(ced);
case _IOC_NR(IOCTL_CED_CHECKSELFTEST):
return ced_check_self_test(ced, (TGET_SELFTEST __user *) arg);
case _IOC_NR(IOCTL_CED_TYPEOF1401):
return ced_type_of_1401(ced);
case _IOC_NR(IOCTL_CED_TRANSFERFLAGS):
return ced_transfer_flags(ced);
case _IOC_NR(IOCTL_CED_DBGPEEK):
return ced_dbg_peek(ced, (TDBGBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_DBGPOKE):
return ced_dbg_poke(ced, (TDBGBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_DBGRAMPDATA):
return ced_dbg_ramp_data(ced, (TDBGBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_DBGRAMPADDR):
return ced_dbg_ramp_addr(ced, (TDBGBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_DBGGETDATA):
return ced_dbg_get_data(ced, (TDBGBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_DBGSTOPLOOP):
return ced_dbg_stop_loop(ced);
case _IOC_NR(IOCTL_CED_FULLRESET):
ced->force_reset = true; /* Set a flag for a full reset */
break;
case _IOC_NR(IOCTL_CED_SETCIRCULAR):
return ced_set_circular(ced,
(struct transfer_area_desc __user *) arg);
case _IOC_NR(IOCTL_CED_GETCIRCBLOCK):
return ced_get_circ_block(ced, (TCIRCBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_FREECIRCBLOCK):
return ced_free_circ_block(ced, (TCIRCBLOCK __user *) arg);
case _IOC_NR(IOCTL_CED_WAITEVENT):
return ced_wait_event(ced, (int)(arg & 0xff), (int)(arg >> 8));
case _IOC_NR(IOCTL_CED_TESTEVENT):
return ced_test_event(ced, (int)arg);
default:
return U14ERR_NO_SUCH_FN;
}
return U14ERR_NOERROR;
}
static const struct file_operations ced_fops = {
.owner = THIS_MODULE,
.open = ced_open,
.release = ced_release,
.flush = ced_flush,
.llseek = noop_llseek,
.unlocked_ioctl = ced_ioctl,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver ced_class = {
.name = "cedusb%d",
.fops = &ced_fops,
.minor_base = USB_CED_MINOR_BASE,
};
/* Check that the device that matches a 1401 vendor and product ID is OK to */
/* use and initialise our struct ced_data. */
static int ced_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct ced_data *ced;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int i, bcdDevice;
int retval = -ENOMEM;
/* allocate memory for our device extension and initialize it */
ced = kzalloc(sizeof(*ced), GFP_KERNEL);
if (!ced)
goto error;
for (i = 0; i < MAX_TRANSAREAS; ++i) { /* Initialise the wait queues */
init_waitqueue_head(&ced->trans_def[i].event);
}
/* Put initialises for our stuff here. Note that all of *ced is
* zero, so no need to explicitly zero it. */
spin_lock_init(&ced->char_out_lock);
spin_lock_init(&ced->char_in_lock);
spin_lock_init(&ced->staged_lock);
/* Initialises from the skeleton stuff */
kref_init(&ced->kref);
mutex_init(&ced->io_mutex);
spin_lock_init(&ced->err_lock);
init_usb_anchor(&ced->submitted);
ced->udev = usb_get_dev(interface_to_usbdev(interface));
ced->interface = interface;
/* Attempt to identify the device */
bcdDevice = ced->udev->descriptor.bcdDevice;
i = (bcdDevice >> 8);
if (i == 0)
ced->type = TYPEU1401;
else if ((i >= 1) && (i <= 23))
ced->type = i + 2;
else {
dev_err(&interface->dev, "%s: Unknown device. bcdDevice = %d\n",
__func__, bcdDevice);
goto error;
}
/* set up the endpoint information. We only care about the number of */
/* EP as we know that we are dealing with a 1401 device. */
iface_desc = interface->cur_altsetting;
ced->n_pipes = iface_desc->desc.bNumEndpoints;
dev_info(&interface->dev, "1401Type=%d with %d End Points\n",
ced->type, ced->n_pipes);
if ((ced->n_pipes < 3) || (ced->n_pipes > 4))
goto error;
/* Allocate the URBs we hold for performing transfers */
ced->urb_char_out = usb_alloc_urb(0, GFP_KERNEL);/* character output
URB */
ced->urb_char_in = usb_alloc_urb(0, GFP_KERNEL); /* character input
URB */
ced->staged_urb = usb_alloc_urb(0, GFP_KERNEL); /* block transfer URB */
if (!ced->urb_char_out || !ced->urb_char_in || !ced->staged_urb) {
dev_err(&interface->dev, "%s: URB alloc failed\n", __func__);
goto error;
}
ced->coher_staged_io =
usb_alloc_coherent(ced->udev, STAGED_SZ, GFP_KERNEL,
&ced->staged_urb->transfer_dma);
ced->coher_char_out =
usb_alloc_coherent(ced->udev, OUTBUF_SZ, GFP_KERNEL,
&ced->urb_char_out->transfer_dma);
ced->coher_char_in =
usb_alloc_coherent(ced->udev, INBUF_SZ, GFP_KERNEL,
&ced->urb_char_in->transfer_dma);
if (!ced->coher_char_out || !ced->coher_char_in ||
!ced->coher_staged_io) {
dev_err(&interface->dev, "%s: Coherent buffer alloc failed\n",
__func__);
goto error;
}
for (i = 0; i < ced->n_pipes; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
ced->ep_addr[i] = endpoint->bEndpointAddress;
dev_info(&interface->dev, "Pipe %d, ep address %02x\n",
i, ced->ep_addr[i]);
/* if char input end point */
if (((ced->n_pipes == 3) && (i == 0)) ||
((ced->n_pipes == 4) && (i == 1))) {
/* save the endpoint interrupt interval */
ced->interval = endpoint->bInterval;
dev_info(&interface->dev, "Pipe %d, interval = %d\n",
i, ced->interval);
}
/* Detect USB2 by checking last ep size (64 if USB1) */
if (i == ced->n_pipes - 1) { /* if this is the last ep (bulk) */
ced->is_usb2 =
le16_to_cpu(endpoint->wMaxPacketSize) > 64;
dev_info(&ced->interface->dev, "USB%d\n",
ced->is_usb2 + 1);
}
}
/* save our data pointer in this interface device */
usb_set_intfdata(interface, ced);
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &ced_class);
if (retval) {
/* something prevented us from registering this driver */
dev_err(&interface->dev,
"Not able to get a minor for this device\n");
usb_set_intfdata(interface, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
dev_info(&interface->dev,
"USB CEDUSB device now attached to cedusb #%d\n",
interface->minor);
return 0;
error:
if (ced)
kref_put(&ced->kref, ced_delete); /* frees allocated memory */
return retval;
}
static void ced_disconnect(struct usb_interface *interface)
{
struct ced_data *ced = usb_get_intfdata(interface);
int minor = interface->minor;
int i;
/* remove the ced from the interface */
usb_set_intfdata(interface, NULL);
/* give back our minor device number */
usb_deregister_dev(interface, &ced_class);
mutex_lock(&ced->io_mutex); /* stop more I/O starting while... */
ced_draw_down(ced); /* ...wait for then kill any io */
for (i = 0; i < MAX_TRANSAREAS; ++i) {
/* ...release any used memory */
int err = ced_clear_area(ced, i);
if (err == U14ERR_UNLOCKFAIL)
dev_err(&ced->interface->dev,
"%s: Area %d was in used\n",
__func__, i);
}
ced->interface = NULL; /* ...we kill off link to interface */
mutex_unlock(&ced->io_mutex);
usb_kill_anchored_urbs(&ced->submitted);
kref_put(&ced->kref, ced_delete); /* decrement our usage count */
dev_info(&interface->dev, "USB cedusb #%d now disconnected\n", minor);
}
/* Wait for all the urbs we know of to be done with, then kill off any that */
/* are left. NBNB we will need to have a mechanism to stop circular xfers */
/* from trying to fire off more urbs. We will wait up to 3 seconds for Urbs */
/* to be done. */
void ced_draw_down(struct ced_data *ced)
{
int time;
dev_dbg(&ced->interface->dev, "%s: called\n", __func__);
ced->in_draw_down = true;
time = usb_wait_anchor_empty_timeout(&ced->submitted, 3000);
if (!time) { /* if we timed out we kill the urbs */
usb_kill_anchored_urbs(&ced->submitted);
dev_err(&ced->interface->dev, "%s: timed out\n", __func__);
}
ced->in_draw_down = false;
}
static int ced_suspend(struct usb_interface *intf, pm_message_t message)
{
struct ced_data *ced = usb_get_intfdata(intf);
if (!ced)
return 0;
ced_draw_down(ced);
dev_dbg(&ced->interface->dev, "%s: called\n", __func__);
return 0;
}
static int ced_resume(struct usb_interface *intf)
{
struct ced_data *ced = usb_get_intfdata(intf);
if (!ced)
return 0;
dev_dbg(&ced->interface->dev, "%s: called\n", __func__);
return 0;
}
static int ced_pre_reset(struct usb_interface *intf)
{
struct ced_data *ced = usb_get_intfdata(intf);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
mutex_lock(&ced->io_mutex);
ced_draw_down(ced);
return 0;
}
static int ced_post_reset(struct usb_interface *intf)
{
struct ced_data *ced = usb_get_intfdata(intf);
dev_dbg(&ced->interface->dev, "%s\n", __func__);
/* we are sure no URBs are active - no locking needed */
ced->errors = -EPIPE;
mutex_unlock(&ced->io_mutex);
return 0;
}
static struct usb_driver ced_driver = {
.name = "cedusb",
.probe = ced_probe,
.disconnect = ced_disconnect,
.suspend = ced_suspend,
.resume = ced_resume,
.pre_reset = ced_pre_reset,
.post_reset = ced_post_reset,
.id_table = ced_table,
.supports_autosuspend = 1,
};
module_usb_driver(ced_driver);
MODULE_LICENSE("GPL");
/* usb1401.h
Header file for the CED 1401 USB device driver for Linux
Copyright (C) 2010 Cambridge Electronic Design Ltd
Author Greg P Smith (greg@ced.co.uk)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __USB1401_H__
#define __USB1401_H__
#include "use1401.h"
#include "ced_ioctl.h"
#ifndef UINT
#define UINT unsigned int
#endif
/** Device type codes, but these don't need to be extended - a succession is assumed
** These are set for usb from the bcdDevice field (suitably mangled). Future devices
** will be added in order of device creation to the list, so the names here are just
** to help use remember which device is which. The U14ERR_... values follow the same
** pattern for modern devices.a
**/
#define TYPEUNKNOWN -1 /* dont know */
#define TYPE1401 0 /* standard 1401 */
#define TYPEPLUS 1 /* 1401 plus */
#define TYPEU1401 2 /* u1401 */
#define TYPEPOWER 3 /* Power1401 */
#define TYPEU14012 4 /* u1401 mkII */
#define TYPEPOWER2 5 /* Power1401 mk II */
#define TYPEMICRO3 6 /* Micro1401-3 */
#define TYPEPOWER3 7 /* Power1401-3 */
/* Some useful defines of constants. DONT FORGET to change the version in the */
/* resources whenever you change it here!. */
#define DRIVERMAJREV 2 /* driver revision level major (match windows) */
#define DRIVERMINREV 0 /* driver revision level minor */
/* Definitions of the various block transfer command codes */
#define TM_EXTTOHOST 8 /* extended tohost */
#define TM_EXTTO1401 9 /* extended to1401 */
/* Definitions of values in usbReqtype. Used in sorting out setup actions */
#define H_TO_D 0x00
#define D_TO_H 0x80
#define VENDOR 0x40
#define DEVREQ 0x00
#define INTREQ 0x01
#define ENDREQ 0x02
/* Definition of values in usbRequest, again used to sort out setup */
#define GET_STATUS 0x00
#define CLEAR_FEATURE 0x01
#define SET_FEATURE 0x03
#define SET_ADDRESS 0x05
#define GET_DESC 0x06
#define SET_DESC 0x07
#define GET_CONF 0x08
#define SET_CONF 0x09
#define GET_INTERFACE 0x0a
#define SET_INTERFACE 0x0b
#define SYNCH_FRAME 0x0c
/* Definitions of the various debug command codes understood by the 1401. These */
/* are used in various vendor-specific commands to achieve the desired effect */
#define DB_GRAB 0x50 /* Grab is a NOP for USB */
#define DB_FREE 0x51 /* Free is a NOP for the USB */
#define DB_SETADD 0x52 /* Set debug address (double) */
#define DB_SELFTEST 0x53 /* Start self test */
#define DB_SETMASK 0x54 /* Set enable mask (double) */
#define DB_SETDEF 0x55 /* Set default mask (double) */
#define DB_PEEK 0x56 /* Peek address, save result */
#define DB_POKE 0x57 /* Poke address with data (double) */
#define DB_RAMPD 0x58 /* Ramp data at debug address */
#define DB_RAMPA 0x59 /* Ramp address bus */
#define DB_REPEATS 0x5A /* Set repeats for operations (double) */
#define DB_WIDTH 0x5B /* Set width for operations (byte) */
#define DB_DATA 0x5C /* Get 4-byte data read by PEEK */
#define DB_CHARS 0x5D /* Send chars via EP0 control write */
#define CR_CHAR 0x0D /* The carriage return character */
#define CR_CHAR_80 0x8d /* and with bit 7 set */
/* A structure holding information about a block */
/* of memory for use in circular transfers */
struct circ_blk {
volatile UINT offset; /* Offset within area of block start */
volatile UINT size; /* Size of the block, in bytes (0 = unused) */
};
/* A structure holding all of the information about a transfer area - an area */
/* of memory set up for use either as a source or destination in DMA */
/* transfers. */
struct transarea {
/* User address of xfer area saved for completeness */
void __user *buff;
/* offset to start of xfer area in first page */
UINT base_offset;
UINT length; /* Length of xfer area, in bytes */
struct page **pages; /* Points at array of locked down pages */
int n_pages; /* number of pages that are locked down */
bool used; /* Is this structure in use? */
bool circular; /* Is this area for circular transfers? */
bool circ_to_host; /* Flag for direction of circular transfer */
bool event_to_host; /* Set event on transfer to host? */
int wake_up; /* Set 1 on event, cleared by TestEvent() */
UINT event_st; /* Defines section within xfer area for... */
UINT event_sz; /* notification by the event SZ is 0 if unset */
struct circ_blk blocks[2]; /* Info on a pair of circular blocks */
wait_queue_head_t event; /* The wait queue for events in this */
/* area MUST BE LAST */
};
/* The dmadesc structure is used to hold information on the transfer in */
/* progress. It is set up by ReadDMAInfo, using information sent by the 1401 */
/* in an escape sequence. */
struct dmadesc {
unsigned short trans_type; /* transfer type as TM_xxx above */
unsigned short ident; /* identifier word */
unsigned int size; /* bytes to transfer */
unsigned int offset; /* offset into transfer area for trans */
bool outward; /* true when data is going TO 1401 */
};
#define INBUF_SZ 256 /* input buffer size */
#define OUTBUF_SZ 256 /* output buffer size */
#define STAGED_SZ 0x10000 /* size of coherent buffer for staged transfers */
/* Structure to hold all of our device specific stuff. We are making this as */
/* similar as we can to the Windows driver to help in our understanding of */
/* what is going on. */
struct ced_data {
char input_buffer[INBUF_SZ]; /* The two buffers */
char output_buffer[OUTBUF_SZ]; /* accessed by the host functions */
volatile unsigned int num_input; /* num of chars in input buffer */
volatile unsigned int in_buff_get; /* where to get from input buffer */
volatile unsigned int in_buff_put; /* where to put into input buffer */
volatile unsigned int num_output; /* num of chars in output buffer */
volatile unsigned int out_buff_get; /* where to get from output buffer*/
volatile unsigned int out_buff_put; /* where to put into output buffer*/
volatile bool send_chars_pending; /* Flag to indicate sendchar active */
volatile bool read_chars_pending; /* Flag to indicate a read is primed*/
char *coher_char_out; /* special aligned buffer for chars to 1401 */
struct urb *urb_char_out; /* urb used for chars to 1401 */
char *coher_char_in; /* special aligned buffer for chars to host */
struct urb *urb_char_in; /* urb used for chars to host */
spinlock_t char_out_lock; /* protect the output_buffer and outputting */
spinlock_t char_in_lock; /* protect the input_buffer and char reads */
__u8 interval; /* Interrupt end point interval */
volatile unsigned int dma_flag; /* state of DMA */
struct transarea trans_def[MAX_TRANSAREAS]; /* transfer area info */
volatile struct dmadesc dma_info; /* info on current DMA transfer */
volatile bool xfer_waiting; /* Flag set if DMA transfer stalled */
volatile bool in_draw_down; /* Flag that we want to halt transfers */
/* Parameters relating to a block read\write that is in progress. Some of these values */
/* are equivalent to values in dma_info. The values here are those in use, while those */
/* in dma_info are those received from the 1401 via an escape sequence. If another */
/* escape sequence arrives before the previous xfer ends, dma_info values are updated while these */
/* are used to finish off the current transfer. */
volatile short staged_id; /* The transfer area id for this transfer */
volatile bool staged_read; /* Flag TRUE for read from 1401, FALSE for write */
volatile unsigned int staged_length; /* Total length of this transfer */
volatile unsigned int staged_offset; /* Offset within memory area for transfer start */
volatile unsigned int staged_done; /* Bytes transferred so far */
volatile bool staged_urb_pending; /* Flag to indicate active */
char *coher_staged_io; /* buffer used for block transfers */
struct urb *staged_urb; /* The URB to use */
spinlock_t staged_lock; /* protects ReadWriteMem() and */
/* circular buffer stuff */
short type; /* type of 1401 attached */
short current_state; /* current error state */
bool is_usb2; /* type of the interface we connect to */
bool force_reset; /* Flag to make sure we get a real reset */
__u32 stat_buf[2]; /* buffer for 1401 state info */
unsigned long self_test_time; /* used to timeout self test */
int n_pipes; /* Should be 3 or 4 depending on 1401 usb chip */
int pipe_error[4]; /* set non-zero if an error on one of the pipe */
__u8 ep_addr[4]; /* addresses of the 3/4 end points */
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device, NULL if removed */
struct usb_anchor submitted; /* in case we need to retract our submissions */
struct mutex io_mutex; /* synchronize I/O with disconnect, one user-mode caller at a time */
int errors; /* the last request tanked */
int open_count; /* count the number of openers */
spinlock_t err_lock; /* lock for errors */
struct kref kref;
};
#define to_ced_data(d) container_of(d, struct ced_data, kref)
/* Definitions of routimes used between compilation object files */
/* in usb1401.c */
extern int ced_allowi(struct ced_data *ced);
extern int ced_send_chars(struct ced_data *ced);
extern void ced_draw_down(struct ced_data *ced);
extern int ced_read_write_mem(struct ced_data *ced, bool read,
unsigned short ident, unsigned int offs,
unsigned int len);
/* in ced_ioc.c */
extern int ced_clear_area(struct ced_data *ced, int area);
extern int ced_send_string(struct ced_data *ced, const char __user *data, unsigned int n);
extern int ced_send_char(struct ced_data *ced, char c);
extern int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error);
extern int ced_read_write_cancel(struct ced_data *ced);
extern int ced_reset(struct ced_data *ced);
extern int ced_get_char(struct ced_data *ced);
extern int ced_get_string(struct ced_data *ced, char __user *user, int n);
extern int ced_set_transfer(struct ced_data *ced,
struct transfer_area_desc __user *utd);
extern int ced_unset_transfer(struct ced_data *ced, int area);
extern int ced_set_event(struct ced_data *ced,
struct transfer_event __user *ute);
extern int ced_stat_1401(struct ced_data *ced);
extern int ced_line_count(struct ced_data *ced);
extern int ced_get_out_buf_space(struct ced_data *ced);
extern int ced_get_transfer(struct ced_data *ced, TGET_TX_BLOCK __user *utx);
extern int ced_kill_io(struct ced_data *ced);
extern int ced_state_of_1401(struct ced_data *ced);
extern int ced_start_self_test(struct ced_data *ced);
extern int ced_check_self_test(struct ced_data *ced,
TGET_SELFTEST __user *ugst);
extern int ced_type_of_1401(struct ced_data *ced);
extern int ced_transfer_flags(struct ced_data *ced);
extern int ced_dbg_peek(struct ced_data *ced, TDBGBLOCK __user *udb);
extern int ced_dbg_poke(struct ced_data *ced, TDBGBLOCK __user *udb);
extern int ced_dbg_ramp_data(struct ced_data *ced, TDBGBLOCK __user *udb);
extern int ced_dbg_ramp_addr(struct ced_data *ced, TDBGBLOCK __user *udb);
extern int ced_dbg_get_data(struct ced_data *ced, TDBGBLOCK __user *udb);
extern int ced_dbg_stop_loop(struct ced_data *ced);
extern int ced_set_circular(struct ced_data *ced,
struct transfer_area_desc __user *utd);
extern int ced_get_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb);
extern int ced_free_circ_block(struct ced_data *ced, TCIRCBLOCK __user *ucb);
extern int ced_wait_event(struct ced_data *ced, int area, int time_out);
extern int ced_test_event(struct ced_data *ced, int area);
#endif
/****************************************************************************
** use1401.h
** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010
** Authors: Paul Cox, Tim Bergel, Greg Smith
** See CVS for revisions.
**
** Because the size of a long is different between 32-bit and 64-bit on some
** systems, we avoid this in this interface.
****************************************************************************/
#ifndef __USE1401_H__
#define __USE1401_H__
#include "machine.h"
/* Some definitions to make things compatible. If you want to use Use1401 directly */
/* from a Windows program you should define U14_NOT_DLL, in which case you also */
/* MUST make sure that your application startup code calls U14InitLib(). */
/* DLL_USE1401 is defined when you are building the Use1401 dll, not otherwise. */
#ifdef _IS_WINDOWS_
#ifndef U14_NOT_DLL
#ifdef DLL_USE1401
#define U14API(retType) (retType DllExport __stdcall)
#else
#define U14API(retType) (retType DllImport __stdcall)
#endif
#endif
#define U14ERRBASE -500
#define U14LONG long
#endif
#ifdef LINUX
#define U14ERRBASE -1000
#define U14LONG int
#endif
#ifdef _QT
#ifndef U14_NOT_DLL
#undef U14API
#define U14API(retType) (retType __declspec(dllimport) __stdcall)
#endif
#undef U14LONG
#define U14LONG int
#endif
#ifndef U14API
#define U14API(retType) retType
#endif
#ifndef U14LONG
#define U14LONG long
#endif
/* Error codes: We need them here as user space can see them. */
#define U14ERR_NOERROR 0 /* no problems */
/* Device error codes, but these don't need to be extended - a succession is assumed */
#define U14ERR_STD 4 /* standard 1401 connected */
#define U14ERR_U1401 5 /* u1401 connected */
#define U14ERR_PLUS 6 /* 1401 plus connected */
#define U14ERR_POWER 7 /* Power1401 connected */
#define U14ERR_U14012 8 /* u1401 mkII connected */
#define U14ERR_POWER2 9
#define U14ERR_U14013 10
#define U14ERR_POWER3 11
/* NBNB Error numbers need shifting as some linux error codes start at 512 */
#define U14ERR(n) (n+U14ERRBASE)
#define U14ERR_OFF U14ERR(0) /* 1401 there but switched off */
#define U14ERR_NC U14ERR(-1) /* 1401 not connected */
#define U14ERR_ILL U14ERR(-2) /* if present it is ill */
#define U14ERR_NOIF U14ERR(-3) /* I/F card missing */
#define U14ERR_TIME U14ERR(-4) /* 1401 failed to come ready */
#define U14ERR_BADSW U14ERR(-5) /* I/F card bad switches */
#define U14ERR_PTIME U14ERR(-6) /* 1401plus failed to come ready */
#define U14ERR_NOINT U14ERR(-7) /* couldn't grab the int vector */
#define U14ERR_INUSE U14ERR(-8) /* 1401 is already in use */
#define U14ERR_NODMA U14ERR(-9) /* couldn't get DMA channel */
#define U14ERR_BADHAND U14ERR(-10) /* handle provided was bad */
#define U14ERR_BAD1401NUM U14ERR(-11) /* 1401 number provided was bad */
#define U14ERR_NO_SUCH_FN U14ERR(-20) /* no such function */
#define U14ERR_NO_SUCH_SUBFN U14ERR(-21) /* no such sub function */
#define U14ERR_NOOUT U14ERR(-22) /* no room in output buffer */
#define U14ERR_NOIN U14ERR(-23) /* no input in buffer */
#define U14ERR_STRLEN U14ERR(-24) /* string longer than buffer */
#define U14ERR_ERR_STRLEN U14ERR(-24) /* string longer than buffer */
#define U14ERR_LOCKFAIL U14ERR(-25) /* failed to lock memory */
#define U14ERR_UNLOCKFAIL U14ERR(-26) /* failed to unlock memory */
#define U14ERR_ALREADYSET U14ERR(-27) /* area already set up */
#define U14ERR_NOTSET U14ERR(-28) /* area not set up */
#define U14ERR_BADAREA U14ERR(-29) /* illegal area number */
#define U14ERR_FAIL U14ERR(-30) /* we failed for some other reason*/
#define U14ERR_NOFILE U14ERR(-40) /* command file not found */
#define U14ERR_READERR U14ERR(-41) /* error reading command file */
#define U14ERR_UNKNOWN U14ERR(-42) /* unknown command */
#define U14ERR_HOSTSPACE U14ERR(-43) /* not enough host space to load */
#define U14ERR_LOCKERR U14ERR(-44) /* could not lock resource/command*/
#define U14ERR_CLOADERR U14ERR(-45) /* CLOAD command failed */
#define U14ERR_TOXXXERR U14ERR(-60) /* tohost/1401 failed */
#define U14ERR_NO386ENH U14ERR(-80) /* not 386 enhanced mode */
#define U14ERR_NO1401DRIV U14ERR(-81) /* no device driver */
#define U14ERR_DRIVTOOOLD U14ERR(-82) /* device driver too old */
#define U14ERR_TIMEOUT U14ERR(-90) /* timeout occurred */
#define U14ERR_BUFF_SMALL U14ERR(-100) /* buffer for getstring too small */
#define U14ERR_CBALREADY U14ERR(-101) /* there is already a callback */
#define U14ERR_BADDEREG U14ERR(-102) /* bad parameter to deregcallback */
#define U14ERR_NOMEMORY U14ERR(-103) /* no memory for allocation */
#define U14ERR_DRIVCOMMS U14ERR(-110) /* failed talking to driver */
#define U14ERR_OUTOFMEMORY U14ERR(-111) /* needed memory and couldnt get it*/
/* / 1401 type codes. */
#define U14TYPE1401 0 /* standard 1401 */
#define U14TYPEPLUS 1 /* 1401 plus */
#define U14TYPEU1401 2 /* u1401 */
#define U14TYPEPOWER 3 /* power1401 */
#define U14TYPEU14012 4 /* u1401 mk II */
#define U14TYPEPOWER2 5 /* power1401 mk II */
#define U14TYPEU14013 6 /* u1401-3 */
#define U14TYPEPOWER3 7 /* power1401-3 */
#define U14TYPEUNKNOWN -1 /* dont know */
/* Transfer flags to allow driver capabilities to be interrogated */
/* Constants for transfer flags */
#define U14TF_USEDMA 1 /* Transfer flag for use DMA */
#define U14TF_MULTIA 2 /* Transfer flag for multi areas */
#define U14TF_FIFO 4 /* for FIFO interface card */
#define U14TF_USB2 8 /* for USB2 interface and 1401 */
#define U14TF_NOTIFY 16 /* for event notifications */
#define U14TF_SHORT 32 /* for PCI can short cycle */
#define U14TF_PCI2 64 /* for new PCI card 1401-70 */
#define U14TF_CIRCTH 128 /* Circular-mode to host */
#define U14TF_DIAG 256 /* Diagnostics/debug functions */
#define U14TF_CIRC14 512 /* Circular-mode to 1401 */
/* Definitions of element sizes for DMA transfers - to allow byte-swapping */
#define ESZBYTES 0 /* BYTE element size value */
#define ESZWORDS 1 /* unsigned short element size value */
#define ESZLONGS 2 /* long element size value */
#define ESZUNKNOWN 0 /* unknown element size value */
/* These define required access types for the debug/diagnostics function */
#define BYTE_SIZE 1 /* 8-bit access */
#define WORD_SIZE 2 /* 16-bit access */
#define LONG_SIZE 3 /* 32-bit access */
/* Stuff used by U14_GetTransfer */
#define GET_TX_MAXENTRIES 257 /* (max length / page size + 1) */
#ifdef _IS_WINDOWS_
#pragma pack(1)
typedef struct /* used for U14_GetTransfer results */
{ /* Info on a single mapped block */
U14LONG physical;
U14LONG size;
} TXENTRY;
typedef struct TGetTxBlock /* used for U14_GetTransfer results */
{ /* matches structure in VXD */
U14LONG size;
U14LONG linear;
short seg;
short reserved;
short avail; /* number of available entries */
short used; /* number of used entries */
TXENTRY entries[GET_TX_MAXENTRIES]; /* Array of mapped block info */
} TGET_TX_BLOCK;
typedef TGET_TX_BLOCK *LPGET_TX_BLOCK;
#pragma pack()
#endif
#ifdef LINUX
typedef struct /* used for U14_GetTransfer results */
{ /* Info on a single mapped block */
long long physical;
long size;
} TXENTRY;
typedef struct TGetTxBlock /* used for U14_GetTransfer results */
{ /* matches structure in VXD */
long long linear; /* linear address */
long size; /* total size of the mapped area, holds id when called */
short seg; /* segment of the address for Win16 */
short reserved;
short avail; /* number of available entries */
short used; /* number of used entries */
TXENTRY entries[GET_TX_MAXENTRIES]; /* Array of mapped block info */
} TGET_TX_BLOCK;
#endif
#ifdef __cplusplus
extern "C" {
#endif
U14API(int) U14WhenToTimeOut(short hand); /* when to timeout in ms */
U14API(short) U14PassedTime(int iTime); /* non-zero if iTime passed */
U14API(short) U14LastErrCode(short hand);
U14API(short) U14Open1401(short n1401);
U14API(short) U14Close1401(short hand);
U14API(short) U14Reset1401(short hand);
U14API(short) U14ForceReset(short hand);
U14API(short) U14TypeOf1401(short hand);
U14API(short) U14NameOf1401(short hand, char *pBuf, unsigned short wMax);
U14API(short) U14Stat1401(short hand);
U14API(short) U14CharCount(short hand);
U14API(short) U14LineCount(short hand);
U14API(short) U14SendString(short hand, const char *pString);
U14API(short) U14GetString(short hand, char *pBuffer, unsigned short wMaxLen);
U14API(short) U14SendChar(short hand, char cChar);
U14API(short) U14GetChar(short hand, char *pcChar);
U14API(short) U14LdCmd(short hand, const char *command);
U14API(unsigned int) U14Ld(short hand, const char *vl, const char *str);
U14API(short) U14SetTransArea(short hand, unsigned short wArea, void *pvBuff,
unsigned int dwLength, short eSz);
U14API(short) U14UnSetTransfer(short hand, unsigned short wArea);
U14API(short) U14SetTransferEvent(short hand, unsigned short wArea, BOOL bEvent,
BOOL bToHost, unsigned int dwStart, unsigned int dwLength);
U14API(int) U14TestTransferEvent(short hand, unsigned short wArea);
U14API(int) U14WaitTransferEvent(short hand, unsigned short wArea, int msTimeOut);
U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock);
U14API(short) U14ToHost(short hand, char *pAddrHost, unsigned int dwSize, unsigned int dw1401,
short eSz);
U14API(short) U14To1401(short hand, const char *pAddrHost, unsigned int dwSize, unsigned int dw1401,
short eSz);
U14API(short) U14SetCircular(short hand, unsigned short wArea, BOOL bToHost, void *pvBuff,
unsigned int dwLength);
U14API(int) U14GetCircBlk(short hand, unsigned short wArea, unsigned int *pdwOffs);
U14API(int) U14FreeCircBlk(short hand, unsigned short wArea, unsigned int dwOffs, unsigned int dwSize,
unsigned int *pdwOffs);
U14API(short) U14StrToLongs(const char *pszBuff, U14LONG *palNums, short sMaxLongs);
U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs);
U14API(void) U14SetTimeout(short hand, int lTimeout);
U14API(int) U14GetTimeout(short hand);
U14API(short) U14OutBufSpace(short hand);
U14API(int) U14BaseAddr1401(short hand);
U14API(int) U14DriverVersion(short hand);
U14API(int) U14DriverType(short hand);
U14API(short) U14DriverName(short hand, char *pBuf, unsigned short wMax);
U14API(short) U14GetUserMemorySize(short hand, unsigned int *pMemorySize);
U14API(short) U14KillIO1401(short hand);
U14API(short) U14BlkTransState(short hand);
U14API(short) U14StateOf1401(short hand);
U14API(short) U14Grab1401(short hand);
U14API(short) U14Free1401(short hand);
U14API(short) U14Peek1401(short hand, unsigned int dwAddr, int nSize, int nRepeats);
U14API(short) U14Poke1401(short hand, unsigned int dwAddr, unsigned int dwValue, int nSize, int nRepeats);
U14API(short) U14Ramp1401(short hand, unsigned int dwAddr, unsigned int dwDef, unsigned int dwEnable, int nSize, int nRepeats);
U14API(short) U14RampAddr(short hand, unsigned int dwDef, unsigned int dwEnable, int nSize, int nRepeats);
U14API(short) U14StopDebugLoop(short hand);
U14API(short) U14GetDebugData(short hand, U14LONG *plValue);
U14API(short) U14StartSelfTest(short hand);
U14API(short) U14CheckSelfTest(short hand, U14LONG *pData);
U14API(short) U14TransferFlags(short hand);
U14API(void) U14GetErrorString(short nErr, char *pStr, unsigned short wMax);
U14API(int) U14MonitorRev(short hand);
U14API(void) U14CloseAll(void);
U14API(short) U14WorkingSet(unsigned int dwMinKb, unsigned int dwMaxKb);
U14API(int) U14InitLib(void);
#ifdef __cplusplus
}
#endif
#endif /* End of ifndef __USE1401_H__ */
/* use14_ioc.h
** definitions of use1401 module stuff that is shared between use1401 and the driver.
** Copyright (C) Cambridge Electronic Design Limited 2010
** Author Greg P Smith
************************************************************************************/
#ifndef __USE14_IOC_H__
#define __USE14_IOC_H__
#define MAX_TRANSAREAS 8 /* The number of transfer areas supported by driver */
#define i386
#include "winioctl.h" /* needed so we can access driver */
/*
** Defines for IOCTL functions to ask driver to perform. These must be matched
** in both use1401 and in the driver. The IOCTL code contains a command
** identifier, plus other information about the device, the type of access
** with which the file must have been opened, and the type of buffering.
** The IOCTL function codes from 0x80 to 0xFF are for developer use.
*/
#define FILE_DEVICE_CED1401 0x8001
FNNUMBASE 0x800
#define U14_OPEN1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_CLOSE1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+1, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SENDSTRING CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_RESET1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+3, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETCHAR CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+4, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SENDCHAR CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+5, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STAT1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+6, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_LINECOUNT CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+7, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETSTRING CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+8, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_REGCALLBACK CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+9, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETMONITORBUF CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+10, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SETTRANSFER CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+11, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_UNSETTRANSFER CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+12, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SETTRANSEVENT CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+13, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETOUTBUFSPACE CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+14, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETBASEADDRESS CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+15, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETDRIVERREVISION CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+16, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETTRANSFER CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+17, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_KILLIO1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+18, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_BLKTRANSSTATE CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+19, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_BYTECOUNT CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+20, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_ZEROBLOCKCOUNT CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+21, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STOPCIRCULAR CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+22, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STATEOF1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+23, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_REGISTERS1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+24, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GRAB1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+25, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_FREE1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+26, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STEP1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+27, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SET1401REGISTERS CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+28, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STEPTILL1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+29, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SETORIN CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+30, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_STARTSELFTEST CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+31, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_CHECKSELFTEST CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+32, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_TYPEOF1401 CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+33, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_TRANSFERFLAGS CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+34, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGPEEK CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+35, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGPOKE CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+36, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGRAMPDATA CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+37, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGRAMPADDR CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+38, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGGETDATA CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+39, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_DBGSTOPLOOP CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+40, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_FULLRESET CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+41, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_SETCIRCULAR CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+42, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_GETCIRCBLK CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+43, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define U14_FREECIRCBLK CTL_CODE(FILE_DEVICE_CED1401, \
FNNUMBASE+44, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
/*--------------- Structures that are shared with the driver ------------- */
#pragma pack(1)
typedef struct /* used for get/set standard 1401 registers */
{
short sPC;
char A;
char X;
char Y;
char stat;
char rubbish;
} T1401REGISTERS;
typedef union /* to communicate with 1401 driver status & control funcs */
{
char chrs[22];
short ints[11];
long longs[5];
T1401REGISTERS registers;
} TCSBLOCK;
typedef TCSBLOCK* LPTCSBLOCK;
typedef struct paramBlk {
short sState;
TCSBLOCK csBlock;
} PARAMBLK;
typedef PARAMBLK* PPARAMBLK;
struct transfer_area_desc /* Structure and type for SetTransArea */
{
unsigned short wArea; /* number of transfer area to set up */
void FAR *lpvBuff; /* address of transfer area */
unsigned int dwLength; /* length of area to set up */
short eSize; /* size to move (for swapping on MAC) */
};
/* This is the structure used to set up a transfer area */
typedef struct VXTransferDesc /* use1401.c and use1432x.x use only */
{
unsigned short wArea; /* number of transfer area to set up */
unsigned short wAddrSel; /* 16 bit selector for area */
unsigned int dwAddrOfs; /* 32 bit offset for area start */
unsigned int dwLength; /* length of area to set up */
} VXTRANSFERDESC;
#pragma pack()
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment