aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/ced1401/usb1401.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ced1401/usb1401.c')
-rw-r--r--drivers/staging/ced1401/usb1401.c1582
1 files changed, 0 insertions, 1582 deletions
diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c
deleted file mode 100644
index 284abc08922c..000000000000
--- a/drivers/staging/ced1401/usb1401.c
+++ /dev/null
@@ -1,1582 +0,0 @@
-/***********************************************************************************
- 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 DEVICE_EXTENSION (named to match Windows use).
-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 CopyUserSpace().
-
-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)
-{
- DEVICE_EXTENSION *pdx = to_DEVICE_EXTENSION(kref);
-
- /* Free up the output buffer, then free the output urb. Note that the interface member */
- /* of pdx will probably be NULL, so cannot be used to get to dev. */
- usb_free_coherent(pdx->udev, OUTBUF_SZ, pdx->pCoherCharOut,
- pdx->pUrbCharOut->transfer_dma);
- usb_free_urb(pdx->pUrbCharOut);
-
- /* Do the same for chan input */
- usb_free_coherent(pdx->udev, INBUF_SZ, pdx->pCoherCharIn,
- pdx->pUrbCharIn->transfer_dma);
- usb_free_urb(pdx->pUrbCharIn);
-
- /* Do the same for the block transfers */
- usb_free_coherent(pdx->udev, STAGED_SZ, pdx->pCoherStagedIO,
- pdx->pStagedUrb->transfer_dma);
- usb_free_urb(pdx->pStagedUrb);
-
- usb_put_dev(pdx->udev);
- kfree(pdx);
-}
-
-/* This is the driver end of the open() call from user space. */
-static int ced_open(struct inode *inode, struct file *file)
-{
- DEVICE_EXTENSION *pdx;
- 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;
- }
-
- pdx = usb_get_intfdata(interface);
- if (!pdx) {
- retval = -ENODEV;
- goto exit;
- }
-
- dev_dbg(&interface->dev, "%s: got pdx\n", __func__);
-
- /* increment our usage count for the device */
- kref_get(&pdx->kref);
-
- /* lock the device to allow correctly handling errors
- * in resumption */
- mutex_lock(&pdx->io_mutex);
-
- if (!pdx->open_count++) {
- retval = usb_autopm_get_interface(interface);
- if (retval) {
- pdx->open_count--;
- mutex_unlock(&pdx->io_mutex);
- kref_put(&pdx->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;
- pdx->open_count--;
- mutex_unlock(&pdx->io_mutex);
- kref_put(&pdx->kref, ced_delete);
- goto exit;
- }
- /* prevent the device from being autosuspended */
-
- /* save our object in the file's private structure */
- file->private_data = pdx;
- mutex_unlock(&pdx->io_mutex);
-
-exit:
- return retval;
-}
-
-static int ced_release(struct inode *inode, struct file *file)
-{
- DEVICE_EXTENSION *pdx = file->private_data;
- if (pdx == NULL)
- return -ENODEV;
-
- dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
- mutex_lock(&pdx->io_mutex);
- if (!--pdx->open_count && pdx->interface) /* Allow autosuspend */
- usb_autopm_put_interface(pdx->interface);
- mutex_unlock(&pdx->io_mutex);
-
- kref_put(&pdx->kref, ced_delete); /* decrement the count on our device */
- return 0;
-}
-
-static int ced_flush(struct file *file, fl_owner_t id)
-{
- int res;
- DEVICE_EXTENSION *pdx = file->private_data;
- if (pdx == NULL)
- return -ENODEV;
-
- dev_dbg(&pdx->interface->dev, "%s: char in pend=%d\n",
- __func__, pdx->bReadCharsPending);
-
- /* wait for io to stop */
- mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s: got io_mutex\n", __func__);
- ced_draw_down(pdx);
-
- /* read out errors, leave subsequent opens a clean slate */
- spin_lock_irq(&pdx->err_lock);
- res = pdx->errors ? (pdx->errors == -EPIPE ? -EPIPE : -EIO) : 0;
- pdx->errors = 0;
- spin_unlock_irq(&pdx->err_lock);
-
- mutex_unlock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s: exit reached\n", __func__);
-
- return res;
-}
-
-/***************************************************************************
-** CanAcceptIoRequests
-** If the device is removed, interface is set NULL. We also clear our pointer
-** from the interface, so we should make sure that pdx 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 CanAcceptIoRequests(DEVICE_EXTENSION *pdx)
-{
- return pdx && pdx->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 *pUrb)
-{
- DEVICE_EXTENSION *pdx = pUrb->context;
- int nGot = pUrb->actual_length; /* what we transferred */
-
- if (pUrb->status) { /* sync/async unlink faults aren't errors */
- if (!
- (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
- || pUrb->status == -ESHUTDOWN)) {
- dev_err(&pdx->interface->dev,
- "%s: nonzero write bulk status received: %d\n",
- __func__, pUrb->status);
- }
-
- spin_lock(&pdx->err_lock);
- pdx->errors = pUrb->status;
- spin_unlock(&pdx->err_lock);
- nGot = 0; /* and tidy up again if so */
-
- spin_lock(&pdx->charOutLock); /* already at irq level */
- pdx->dwOutBuffGet = 0; /* Reset the output buffer */
- pdx->dwOutBuffPut = 0;
- pdx->dwNumOutput = 0; /* Clear the char count */
- pdx->bPipeError[0] = 1; /* Flag an error for later */
- pdx->bSendCharsPending = false; /* Allow other threads again */
- spin_unlock(&pdx->charOutLock); /* already at irq level */
- dev_dbg(&pdx->interface->dev,
- "%s: char out done, 0 chars sent\n", __func__);
- } else {
- dev_dbg(&pdx->interface->dev,
- "%s: char out done, %d chars sent\n", __func__, nGot);
- spin_lock(&pdx->charOutLock); /* already at irq level */
- pdx->dwNumOutput -= nGot; /* Now adjust the char send buffer */
- pdx->dwOutBuffGet += nGot; /* to match what we did */
- if (pdx->dwOutBuffGet >= OUTBUF_SZ) /* Can't do this any earlier as data could be overwritten */
- pdx->dwOutBuffGet = 0;
-
- if (pdx->dwNumOutput > 0) { /* if more to be done... */
- int nPipe = 0; /* The pipe number to use */
- int iReturn;
- char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet];
- unsigned int dwCount = pdx->dwNumOutput; /* maximum to send */
- if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ) /* does it cross buffer end? */
- dwCount = OUTBUF_SZ - pdx->dwOutBuffGet;
- spin_unlock(&pdx->charOutLock); /* we are done with stuff that changes */
- memcpy(pdx->pCoherCharOut, pDat, dwCount); /* copy output data to the buffer */
- usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev,
- usb_sndbulkpipe(pdx->udev,
- pdx->epAddr[0]),
- pdx->pCoherCharOut, dwCount,
- ced_writechar_callback, pdx);
- pdx->pUrbCharOut->transfer_flags |=
- URB_NO_TRANSFER_DMA_MAP;
- usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted); /* in case we need to kill it */
- iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC);
- dev_dbg(&pdx->interface->dev, "%s: n=%d>%s<\n",
- __func__, dwCount, pDat);
- spin_lock(&pdx->charOutLock); /* grab lock for errors */
- if (iReturn) {
- pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
- pdx->bSendCharsPending = false; /* Allow other threads again */
- usb_unanchor_urb(pdx->pUrbCharOut);
- dev_err(&pdx->interface->dev,
- "%s: usb_submit_urb() returned %d\n",
- __func__, iReturn);
- }
- } else
- pdx->bSendCharsPending = false; /* Allow other threads again */
- spin_unlock(&pdx->charOutLock); /* already at irq level */
- }
-}
-
-/****************************************************************************
-** SendChars
-** Transmit the characters in the output buffer to the 1401. This may need
-** breaking down into multiple transfers.
-****************************************************************************/
-int SendChars(DEVICE_EXTENSION *pdx)
-{
- int iReturn = U14ERR_NOERROR;
-
- spin_lock_irq(&pdx->charOutLock); /* Protect ourselves */
-
- if ((!pdx->bSendCharsPending) && /* Not currently sending */
- (pdx->dwNumOutput > 0) && /* has characters to output */
- (CanAcceptIoRequests(pdx))) { /* and current activity is OK */
- unsigned int dwCount = pdx->dwNumOutput; /* Get a copy of the character count */
- pdx->bSendCharsPending = true; /* Set flag to lock out other threads */
-
- dev_dbg(&pdx->interface->dev,
- "Send %d chars to 1401, EP0 flag %d\n",
- dwCount, pdx->nPipes == 3);
- /* If we have only 3 end points we must send the characters to the 1401 using EP0. */
- if (pdx->nPipes == 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 count = dwCount; /* Local char counter */
- unsigned int index = 0; /* The index into the char buffer */
-
- spin_unlock_irq(&pdx->charOutLock); /* Free spinlock as we call USBD */
-
- while ((count > 0) && (iReturn == U14ERR_NOERROR)) {
- /* We have to break the transfer up into 64-byte chunks because of a 2270 problem */
- int n = count > 64 ? 64 : count; /* Chars for this xfer, max of 64 */
- int nSent = usb_control_msg(pdx->udev,
- usb_sndctrlpipe(pdx->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 */
- &pdx->outputBuffer[index], /* where to send from */
- n, /* how much to send */
- 1000); /* timeout in jiffies */
- if (nSent <= 0) {
- iReturn = nSent ? nSent : -ETIMEDOUT; /* if 0 chars says we timed out */
- dev_err(&pdx->interface->dev,
- "Send %d chars by EP0 failed: %d\n",
- n, iReturn);
- } else {
- dev_dbg(&pdx->interface->dev,
- "Sent %d chars by EP0\n", n);
- count -= nSent;
- index += nSent;
- }
- }
-
- spin_lock_irq(&pdx->charOutLock); /* Protect pdx changes, released by general code */
- pdx->dwOutBuffGet = 0; /* so reset the output buffer */
- pdx->dwOutBuffPut = 0;
- pdx->dwNumOutput = 0; /* and clear the buffer count */
- pdx->bSendCharsPending = false; /* Allow other threads again */
- } else { /* Here for sending chars normally - we hold the spin lock */
- int nPipe = 0; /* The pipe number to use */
- char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet];
-
- if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ) /* does it cross buffer end? */
- dwCount = OUTBUF_SZ - pdx->dwOutBuffGet;
- spin_unlock_irq(&pdx->charOutLock); /* we are done with stuff that changes */
- memcpy(pdx->pCoherCharOut, pDat, dwCount); /* copy output data to the buffer */
- usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev,
- usb_sndbulkpipe(pdx->udev,
- pdx->epAddr[0]),
- pdx->pCoherCharOut, dwCount,
- ced_writechar_callback, pdx);
- pdx->pUrbCharOut->transfer_flags |=
- URB_NO_TRANSFER_DMA_MAP;
- usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted);
- iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_KERNEL);
- spin_lock_irq(&pdx->charOutLock); /* grab lock for errors */
- if (iReturn) {
- pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
- pdx->bSendCharsPending = false; /* Allow other threads again */
- usb_unanchor_urb(pdx->pUrbCharOut); /* remove from list of active urbs */
- }
- }
- } else if (pdx->bSendCharsPending && (pdx->dwNumOutput > 0))
- dev_dbg(&pdx->interface->dev,
- "%s: bSendCharsPending:true\n", __func__);
-
- dev_dbg(&pdx->interface->dev, "%s: exit code: %d\n", __func__, iReturn);
- spin_unlock_irq(&pdx->charOutLock); /* Now let go of the spinlock */
- return iReturn;
-}
-
-/***************************************************************************
-** CopyUserSpace
-** This moves memory between pinned down user space and the pCoherStagedIO
-** memory buffer we use for transfers. Copy n bytes in the directions that
-** is defined by pdx->StagedRead. The user space is determined by the area
-** in pdx->StagedId and the offset in pdx->StagedDone. 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.
-**
-** pdx 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 CopyUserSpace(DEVICE_EXTENSION *pdx, int n)
-{
- unsigned int nArea = pdx->StagedId;
- if (nArea < MAX_TRANSAREAS) {
- TRANSAREA *pArea = &pdx->rTransDef[nArea]; /* area to be used */
- unsigned int dwOffset =
- pdx->StagedDone + pdx->StagedOffset + pArea->dwBaseOffset;
- char *pCoherBuf = pdx->pCoherStagedIO; /* coherent buffer */
- if (!pArea->bUsed) {
- dev_err(&pdx->interface->dev, "%s: area %d unused\n",
- __func__, nArea);
- return;
- }
-
- while (n) {
- int nPage = dwOffset >> PAGE_SHIFT; /* page number in table */
- if (nPage < pArea->nPages) {
- char *pvAddress =
- (char *)kmap_atomic(pArea->pPages[nPage]);
- if (pvAddress) {
- unsigned int uiPageOff = dwOffset & (PAGE_SIZE - 1); /* offset into the page */
- size_t uiXfer = PAGE_SIZE - uiPageOff; /* max to transfer on this page */
- if (uiXfer > n) /* limit byte count if too much */
- uiXfer = n; /* for the page */
- if (pdx->StagedRead)
- memcpy(pvAddress + uiPageOff,
- pCoherBuf, uiXfer);
- else
- memcpy(pCoherBuf,
- pvAddress + uiPageOff,
- uiXfer);
- kunmap_atomic(pvAddress);
- dwOffset += uiXfer;
- pCoherBuf += uiXfer;
- n -= uiXfer;
- } else {
- dev_err(&pdx->interface->dev,
- "%s: did not map page %d\n",
- __func__, nPage);
- return;
- }
-
- } else {
- dev_err(&pdx->interface->dev,
- "%s: exceeded pages %d\n",
- __func__, nPage);
- return;
- }
- }
- } else
- dev_err(&pdx->interface->dev, "%s: bad area %d\n",
- __func__, nArea);
-}
-
-/* Forward declarations for stuff used circularly */
-static int StageChunk(DEVICE_EXTENSION *pdx);
-/***************************************************************************
-** ReadWrite_Complete
-**
-** Completion routine for our staged read/write Irps
-*/
-static void staged_callback(struct urb *pUrb)
-{
- DEVICE_EXTENSION *pdx = pUrb->context;
- unsigned int nGot = pUrb->actual_length; /* what we transferred */
- bool bCancel = false;
- bool bRestartCharInput; /* used at the end */
-
- spin_lock(&pdx->stagedLock); /* stop ReadWriteMem() action while this routine is running */
- pdx->bStagedUrbPending = false; /* clear the flag for staged IRP pending */
-
- if (pUrb->status) { /* sync/async unlink faults aren't errors */
- if (!
- (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
- || pUrb->status == -ESHUTDOWN)) {
- dev_err(&pdx->interface->dev,
- "%s: nonzero write bulk status received: %d\n",
- __func__, pUrb->status);
- } else
- dev_info(&pdx->interface->dev,
- "%s: staged xfer cancelled\n", __func__);
-
- spin_lock(&pdx->err_lock);
- pdx->errors = pUrb->status;
- spin_unlock(&pdx->err_lock);
- nGot = 0; /* and tidy up again if so */
- bCancel = true;
- } else {
- dev_dbg(&pdx->interface->dev, "%s: %d chars xferred\n",
- __func__, nGot);
- if (pdx->StagedRead) /* if reading, save to user space */
- CopyUserSpace(pdx, nGot); /* copy from buffer to user */
- if (nGot == 0)
- dev_dbg(&pdx->interface->dev, "%s: ZLP\n", __func__);
- }
-
- /* Update the transfer length based on the TransferBufferLength value in the URB */
- pdx->StagedDone += nGot;
-
- dev_dbg(&pdx->interface->dev, "%s: done %d bytes of %d\n",
- __func__, pdx->StagedDone, pdx->StagedLength);
-
- if ((pdx->StagedDone == pdx->StagedLength) || /* If no more to do */
- (bCancel)) { /* or this IRP was cancelled */
- TRANSAREA *pArea = &pdx->rTransDef[pdx->StagedId]; /* Transfer area info */
- dev_dbg(&pdx->interface->dev,
- "%s: transfer done, bytes %d, cancel %d\n",
- __func__, pdx->StagedDone, bCancel);
-
- /* 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 ReadWriteMem) is totally duff. */
- if ((pArea->bCircular) && (pArea->bCircToHost) && (!bCancel) && /* Time to sort out circular buffer info? */
- (pdx->StagedRead)) { /* Only for tohost transfers for now */
- if (pArea->aBlocks[1].dwSize > 0) { /* If block 1 is in use we must append to it */
- if (pdx->StagedOffset ==
- (pArea->aBlocks[1].dwOffset +
- pArea->aBlocks[1].dwSize)) {
- pArea->aBlocks[1].dwSize +=
- pdx->StagedLength;
- dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 1 now %d bytes at %d\n",
- pArea->aBlocks[1].dwSize,
- pArea->aBlocks[1].dwOffset);
- } else {
- /* Here things have gone very, very, wrong, but I cannot see how this can actually be achieved */
- pArea->aBlocks[1].dwOffset =
- pdx->StagedOffset;
- pArea->aBlocks[1].dwSize =
- pdx->StagedLength;
- dev_err(&pdx->interface->dev,
- "%s: ERROR, circ block 1 re-started %d bytes at %d\n",
- __func__,
- pArea->aBlocks[1].dwSize,
- pArea->aBlocks[1].dwOffset);
- }
- } else { /* If block 1 is not used, we try to add to block 0 */
- if (pArea->aBlocks[0].dwSize > 0) { /* Got stored block 0 information? */
- /* Must append onto the existing block 0 */
- if (pdx->StagedOffset ==
- (pArea->aBlocks[0].dwOffset +
- pArea->aBlocks[0].dwSize)) {
- pArea->aBlocks[0].dwSize += pdx->StagedLength; /* Just add this transfer in */
- dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 0 now %d bytes at %d\n",
- pArea->aBlocks[0].
- dwSize,
- pArea->aBlocks[0].
- dwOffset);
- } else { /* If it doesn't append, put into new block 1 */
- pArea->aBlocks[1].dwOffset =
- pdx->StagedOffset;
- pArea->aBlocks[1].dwSize =
- pdx->StagedLength;
- dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 1 started %d bytes at %d\n",
- pArea->aBlocks[1].
- dwSize,
- pArea->aBlocks[1].
- dwOffset);
- }
- } else { /* No info stored yet, just save in block 0 */
- pArea->aBlocks[0].dwOffset =
- pdx->StagedOffset;
- pArea->aBlocks[0].dwSize =
- pdx->StagedLength;
- dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 0 started %d bytes at %d\n",
- pArea->aBlocks[0].dwSize,
- pArea->aBlocks[0].dwOffset);
- }
- }
- }
-
- if (!bCancel) { /* Don't generate an event if cancelled */
- dev_dbg(&pdx->interface->dev,
- "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d\n",
- pArea->bCircular, pArea->bEventToHost,
- pArea->dwEventSt, pArea->dwEventSz);
- if ((pArea->dwEventSz) && /* Set a user-mode event... */
- (pdx->StagedRead == pArea->bEventToHost)) { /* ...on transfers in this direction? */
- int iWakeUp = 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 ((pArea->bCircular) && /* Circular areas use a simpler test */
- (pArea->bCircToHost)) { /* only in supported direction */
- /* Is total data waiting up to size limit? */
- unsigned int dwTotal =
- pArea->aBlocks[0].dwSize +
- pArea->aBlocks[1].dwSize;
- iWakeUp = (dwTotal >= pArea->dwEventSz);
- } else {
- unsigned int transEnd =
- pdx->StagedOffset +
- pdx->StagedLength;
- unsigned int eventEnd =
- pArea->dwEventSt + pArea->dwEventSz;
- iWakeUp = (pdx->StagedOffset < eventEnd)
- && (transEnd > pArea->dwEventSt);
- }
-
- if (iWakeUp) {
- dev_dbg(&pdx->interface->dev,
- "About to set event to notify app\n");
- wake_up_interruptible(&pArea->wqEvent); /* wake up waiting processes */
- ++pArea->iWakeUp; /* increment wakeup count */
- }
- }
- }
-
- pdx->dwDMAFlag = MODE_CHAR; /* Switch back to char mode before ReadWriteMem call */
-
- if (!bCancel) { /* Don't look for waiting transfer if cancelled */
- /* If we have a transfer waiting, kick it off */
- if (pdx->bXFerWaiting) { /* Got a block xfer waiting? */
- int iReturn;
- dev_info(&pdx->interface->dev,
- "*** RWM_Complete *** pending transfer will now be set up!!!\n");
- iReturn =
- ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard,
- pdx->rDMAInfo.wIdent,
- pdx->rDMAInfo.dwOffset,
- pdx->rDMAInfo.dwSize);
-
- if (iReturn)
- dev_err(&pdx->interface->dev,
- "RWM_Complete rw setup failed %d\n",
- iReturn);
- }
- }
-
- } else /* Here for more to do */
- StageChunk(pdx); /* fire off the next bit */
-
- /* While we hold the stagedLock, 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 dwDMAFlag. */
- bRestartCharInput = !bCancel && (pdx->dwDMAFlag == MODE_CHAR)
- && !pdx->bXFerWaiting;
-
- spin_unlock(&pdx->stagedLock); /* Finally release the lock again */
-
- /* This is not correct as dwDMAFlag is protected by the staged lock, but it is treated */
- /* in 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 (bRestartCharInput) /* may be out of date, but... */
- Allowi(pdx); /* ...Allowi tests a lock too. */
- dev_dbg(&pdx->interface->dev, "%s: done\n", __func__);
-}
-
-/****************************************************************************
-** StageChunk
-**
-** 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 StageChunk(DEVICE_EXTENSION *pdx)
-{
- int iReturn = U14ERR_NOERROR;
- unsigned int ChunkSize;
- int nPipe = pdx->StagedRead ? 3 : 2; /* The pipe number to use for reads or writes */
- if (pdx->nPipes == 3)
- nPipe--; /* Adjust for the 3-pipe case */
- if (nPipe < 0) /* and trap case that should never happen */
- return U14ERR_FAIL;
-
- if (!CanAcceptIoRequests(pdx)) { /* got sudden remove? */
- dev_info(&pdx->interface->dev, "%s: sudden remove, giving up\n",
- __func__);
- return U14ERR_FAIL; /* could do with a better error */
- }
-
- ChunkSize = (pdx->StagedLength - pdx->StagedDone); /* transfer length remaining */
- if (ChunkSize > STAGED_SZ) /* make sure to keep legal */
- ChunkSize = STAGED_SZ; /* limit to max allowed */
-
- if (!pdx->StagedRead) /* if writing... */
- CopyUserSpace(pdx, ChunkSize); /* ...copy data into the buffer */
-
- usb_fill_bulk_urb(pdx->pStagedUrb, pdx->udev,
- pdx->StagedRead ? usb_rcvbulkpipe(pdx->udev,
- pdx->
- epAddr[nPipe]) :
- usb_sndbulkpipe(pdx->udev, pdx->epAddr[nPipe]),
- pdx->pCoherStagedIO, ChunkSize, staged_callback, pdx);
- pdx->pStagedUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- usb_anchor_urb(pdx->pStagedUrb, &pdx->submitted); /* in case we need to kill it */
- iReturn = usb_submit_urb(pdx->pStagedUrb, GFP_ATOMIC);
- if (iReturn) {
- usb_unanchor_urb(pdx->pStagedUrb); /* kill it */
- pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
- dev_err(&pdx->interface->dev, "%s: submit urb failed, code %d\n",
- __func__, iReturn);
- } else
- pdx->bStagedUrbPending = true; /* Set the flag for staged URB pending */
- dev_dbg(&pdx->interface->dev, "%s: done so far:%d, this size:%d\n",
- __func__, pdx->StagedDone, ChunkSize);
-
- return iReturn;
-}
-
-/***************************************************************************
-** ReadWriteMem
-**
-** 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 stagedLock
-**
-** Arguments:
-** DeviceObject - pointer to our FDO (Functional Device Object)
-** Read - TRUE for read, FALSE for write. This is from POV of the driver
-** wIdent - the transfer area number - defines memory area and more.
-** dwOffs - the start offset within the transfer area of the start of this
-** transfer.
-** dwLen - the number of bytes to transfer.
-*/
-int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
- unsigned int dwOffs, unsigned int dwLen)
-{
- TRANSAREA *pArea = &pdx->rTransDef[wIdent]; /* Transfer area info */
-
- if (!CanAcceptIoRequests(pdx)) { /* Are we in a state to accept new requests? */
- dev_err(&pdx->interface->dev, "%s: can't accept requests\n",
- __func__);
- return U14ERR_FAIL;
- }
-
- dev_dbg(&pdx->interface->dev,
- "%s: xfer %d bytes to %s, offset %d, area %d\n",
- __func__, dwLen, Read ? "host" : "1401", dwOffs, wIdent);
-
- /* 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 (pdx->bStagedUrbPending) {
- pdx->bXFerWaiting = true; /* Flag we are waiting */
- dev_info(&pdx->interface->dev,
- "%s: xfer is waiting, as previous staged pending\n",
- __func__);
- return U14ERR_NOERROR;
- }
-
- if (dwLen == 0) { /* allow 0-len read or write; just return success */
- dev_dbg(&pdx->interface->dev,
- "%s: OK; zero-len read/write request\n", __func__);
- return U14ERR_NOERROR;
- }
-
- if ((pArea->bCircular) && /* Circular transfer? */
- (pArea->bCircToHost) && (Read)) { /* In a supported direction */
- /* If so, we sort out offset ourself */
- bool bWait = false; /* Flag for transfer having to wait */
-
- dev_dbg(&pdx->interface->dev,
- "Circular buffers are %d at %d and %d at %d\n",
- pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset,
- pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset);
- if (pArea->aBlocks[1].dwSize > 0) { /* Using the second block already? */
- dwOffs = pArea->aBlocks[1].dwOffset + pArea->aBlocks[1].dwSize; /* take offset from that */
- bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset; /* Wait if will overwrite block 0? */
- bWait |= (dwOffs + dwLen) > pArea->dwLength; /* or if it overflows the buffer */
- } else { /* Area 1 not in use, try to use area 0 */
- if (pArea->aBlocks[0].dwSize == 0) /* Reset block 0 if not in use */
- pArea->aBlocks[0].dwOffset = 0;
- dwOffs =
- pArea->aBlocks[0].dwOffset +
- pArea->aBlocks[0].dwSize;
- if ((dwOffs + dwLen) > pArea->dwLength) { /* Off the end of the buffer? */
- pArea->aBlocks[1].dwOffset = 0; /* Set up to use second block */
- dwOffs = 0;
- bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset; /* Wait if will overwrite block 0? */
- bWait |= (dwOffs + dwLen) > pArea->dwLength; /* or if it overflows the buffer */
- }
- }
-
- if (bWait) { /* This transfer will have to wait? */
- pdx->bXFerWaiting = true; /* Flag we are waiting */
- dev_dbg(&pdx->interface->dev,
- "%s: xfer waiting for circular buffer space\n",
- __func__);
- return U14ERR_NOERROR;
- }
-
- dev_dbg(&pdx->interface->dev,
- "%s: circular xfer, %d bytes starting at %d\n",
- __func__, dwLen, dwOffs);
- }
- /* Save the parameters for the read\write transfer */
- pdx->StagedRead = Read; /* Save the parameters for this read */
- pdx->StagedId = wIdent; /* ID allows us to get transfer area info */
- pdx->StagedOffset = dwOffs; /* The area within the transfer area */
- pdx->StagedLength = dwLen;
- pdx->StagedDone = 0; /* Initialise the byte count */
- pdx->dwDMAFlag = MODE_LINEAR; /* Set DMA mode flag at this point */
- pdx->bXFerWaiting = false; /* Clearly not a transfer waiting now */
-
-/* KeClearEvent(&pdx->StagingDoneEvent); // Clear the transfer done event */
- StageChunk(pdx); /* fire off the first chunk */
-
- return U14ERR_NOERROR;
-}
-
-/****************************************************************************
-**
-** ReadChar
-**
-** Reads a character a buffer. If there is no more
-** data we return FALSE. Used as part of decoding a DMA request.
-**
-****************************************************************************/
-static bool ReadChar(unsigned char *pChar, char *pBuf, unsigned int *pdDone,
- unsigned int dGot)
-{
- bool bRead = false;
- unsigned int dDone = *pdDone;
-
- if (dDone < dGot) { /* If there is more data */
- *pChar = (unsigned char)pBuf[dDone]; /* Extract the next char */
- dDone++; /* Increment the done count */
- *pdDone = dDone;
- bRead = true; /* and flag success */
- }
-
- return bRead;
-}
-
-#ifdef NOTUSED
-/****************************************************************************
-**
-** ReadWord
-**
-** Reads a word from the 1401, just uses ReadChar twice; passes on any error
-**
-*****************************************************************************/
-static bool ReadWord(unsigned short *pWord, char *pBuf, unsigned int *pdDone,
- unsigned int dGot)
-{
- if (ReadChar((unsigned char *)pWord, pBuf, pdDone, dGot))
- return ReadChar(((unsigned char *)pWord) + 1, pBuf, pdDone,
- dGot);
- else
- return false;
-}
-#endif
-
-/****************************************************************************
-** ReadHuff
-**
-** 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 ReadHuff(volatile unsigned int *pDWord, char *pBuf,
- unsigned int *pdDone, unsigned int dGot)
-{
- unsigned char ucData; /* for each read to ReadChar */
- bool bReturn = true; /* assume we will succeed */
- unsigned int dwData = 0; /* Accumulator for the data */
-
- if (ReadChar(&ucData, pBuf, pdDone, dGot)) {
- dwData = ucData; /* copy the data */
- if ((dwData & 0x00000080) != 0) { /* Bit set for more data ? */
- dwData &= 0x0000007F; /* Clear the relevant bit */
- if (ReadChar(&ucData, pBuf, pdDone, dGot)) {
- dwData = (dwData << 8) | ucData;
- if ((dwData & 0x00004000) != 0) { /* three byte sequence ? */
- dwData &= 0x00003FFF; /* Clear the relevant bit */
- if (ReadChar
- (&ucData, pBuf, pdDone, dGot))
- dwData = (dwData << 8) | ucData;
- else
- bReturn = false;
- }
- } else
- bReturn = false; /* couldn't read data */
- }
- } else
- bReturn = false;
-
- *pDWord = dwData; /* return the data */
- return bReturn;
-}
-
-/***************************************************************************
-**
-** ReadDMAInfo
-**
-** 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 pBuf char pointer does not include the initial escape character, so
-** we start handling the data at offset zero.
-**
-*****************************************************************************/
-static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
- char *pBuf, unsigned int dwCount)
-{
- bool bResult = false; /* assume we won't succeed */
- unsigned char ucData;
- unsigned int dDone = 0; /* We haven't parsed anything so far */
-
- dev_dbg(&pdx->interface->dev, "%s\n", __func__);
-
- if (ReadChar(&ucData, pBuf, &dDone, dwCount)) {
- unsigned char ucTransCode = (ucData & 0x0F); /* get code for transfer type */
- unsigned short wIdent = ((ucData >> 4) & 0x07); /* and area identifier */
-
- /* fill in the structure we were given */
- pDmaDesc->wTransType = ucTransCode; /* type of transfer */
- pDmaDesc->wIdent = wIdent; /* area to use */
- pDmaDesc->dwSize = 0; /* initialise other bits */
- pDmaDesc->dwOffset = 0;
-
- dev_dbg(&pdx->interface->dev, "%s: type: %d ident: %d\n",
- __func__, pDmaDesc->wTransType, pDmaDesc->wIdent);
-
- pDmaDesc->bOutWard = (ucTransCode != TM_EXTTOHOST); /* set transfer direction */
-
- switch (ucTransCode) {
- case TM_EXTTOHOST: /* Extended linear transfer modes (the only ones!) */
- case TM_EXTTO1401:
- {
- bResult =
- ReadHuff(&(pDmaDesc->dwOffset), pBuf,
- &dDone, dwCount)
- && ReadHuff(&(pDmaDesc->dwSize), pBuf,
- &dDone, dwCount);
- if (bResult) {
- dev_dbg(&pdx->interface->dev,
- "%s: xfer offset & size %d %d\n",
- __func__, pDmaDesc->dwOffset,
- pDmaDesc->dwSize);
-
- if ((wIdent >= MAX_TRANSAREAS) || /* Illegal area number, or... */
- (!pdx->rTransDef[wIdent].bUsed) || /* area not set up, or... */
- (pDmaDesc->dwOffset > pdx->rTransDef[wIdent].dwLength) || /* range/size */
- ((pDmaDesc->dwOffset +
- pDmaDesc->dwSize) >
- (pdx->rTransDef[wIdent].
- dwLength))) {
- bResult = false; /* bad parameter(s) */
- dev_dbg(&pdx->interface->dev,
- "%s: bad param - id %d, bUsed %d, offset %d, size %d, area length %d\n",
- __func__, wIdent,
- pdx->rTransDef[wIdent].
- bUsed,
- pDmaDesc->dwOffset,
- pDmaDesc->dwSize,
- pdx->rTransDef[wIdent].
- dwLength);
- }
- }
- break;
- }
- default:
- break;
- }
- } else
- bResult = false;
-
- if (!bResult) /* now check parameters for validity */
- dev_err(&pdx->interface->dev, "%s: error reading Esc sequence\n",
- __func__);
-
- return bResult;
-}
-
-/****************************************************************************
-**
-** Handle1401Esc
-**
-** 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
-**
-** dwCount - 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 Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh,
- unsigned int dwCount)
-{
- int iReturn = 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 (pCh[0] == '?') { /* Is this an information response */
- /* Parse and save the information */
- } else {
- spin_lock(&pdx->stagedLock); /* Lock others out */
-
- if (ReadDMAInfo(&pdx->rDMAInfo, pdx, pCh, dwCount)) { /* Get DMA parameters */
- unsigned short wTransType = pdx->rDMAInfo.wTransType; /* check transfer type */
-
- dev_dbg(&pdx->interface->dev,
- "%s: xfer to %s, offset %d, length %d\n",
- __func__,
- pdx->rDMAInfo.bOutWard ? "1401" : "host",
- pdx->rDMAInfo.dwOffset, pdx->rDMAInfo.dwSize);
-
- if (pdx->bXFerWaiting) { /* Check here for badly out of kilter... */
- /* This can never happen, really */
- dev_err(&pdx->interface->dev,
- "ERROR: DMA setup while transfer still waiting\n");
- } else {
- if ((wTransType == TM_EXTTOHOST)
- || (wTransType == TM_EXTTO1401)) {
- iReturn =
- ReadWriteMem(pdx,
- !pdx->rDMAInfo.
- bOutWard,
- pdx->rDMAInfo.wIdent,
- pdx->rDMAInfo.dwOffset,
- pdx->rDMAInfo.dwSize);
- if (iReturn != U14ERR_NOERROR)
- dev_err(&pdx->interface->dev,
- "%s: ReadWriteMem() failed %d\n",
- __func__, iReturn);
- } else /* This covers non-linear transfer setup */
- dev_err(&pdx->interface->dev,
- "%s: Unknown block xfer type %d\n",
- __func__, wTransType);
- }
- } else /* Failed to read parameters */
- dev_err(&pdx->interface->dev, "%s: ReadDMAInfo() fail\n",
- __func__);
-
- spin_unlock(&pdx->stagedLock); /* OK here */
- }
-
- dev_dbg(&pdx->interface->dev, "%s: returns %d\n", __func__, iReturn);
-
- return iReturn;
-}
-
-/****************************************************************************
-** Callback for the character read complete or error
-****************************************************************************/
-static void ced_readchar_callback(struct urb *pUrb)
-{
- DEVICE_EXTENSION *pdx = pUrb->context;
- int nGot = pUrb->actual_length; /* what we transferred */
-
- if (pUrb->status) { /* Do we have a problem to handle? */
- int nPipe = pdx->nPipes == 4 ? 1 : 0; /* The pipe number to use for error */
- /* sync/async unlink faults aren't errors... just saying device removed or stopped */
- if (!
- (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
- || pUrb->status == -ESHUTDOWN)) {
- dev_err(&pdx->interface->dev,
- "%s: nonzero write bulk status received: %d\n",
- __func__, pUrb->status);
- } else
- dev_dbg(&pdx->interface->dev,
- "%s: 0 chars pUrb->status=%d (shutdown?)\n",
- __func__, pUrb->status);
-
- spin_lock(&pdx->err_lock);
- pdx->errors = pUrb->status;
- spin_unlock(&pdx->err_lock);
- nGot = 0; /* and tidy up again if so */
-
- spin_lock(&pdx->charInLock); /* already at irq level */
- pdx->bPipeError[nPipe] = 1; /* Flag an error for later */
- } else {
- if ((nGot > 1) && ((pdx->pCoherCharIn[0] & 0x7f) == 0x1b)) { /* Esc sequence? */
- Handle1401Esc(pdx, &pdx->pCoherCharIn[1], nGot - 1); /* handle it */
- spin_lock(&pdx->charInLock); /* already at irq level */
- } else {
- spin_lock(&pdx->charInLock); /* already at irq level */
- if (nGot > 0) {
- unsigned int i;
- if (nGot < INBUF_SZ) {
- pdx->pCoherCharIn[nGot] = 0; /* tidy the string */
- dev_dbg(&pdx->interface->dev,
- "%s: got %d chars >%s<\n",
- __func__, nGot,
- pdx->pCoherCharIn);
- }
- /* We know that whatever we read must fit in the input buffer */
- for (i = 0; i < nGot; i++) {
- pdx->inputBuffer[pdx->dwInBuffPut++] =
- pdx->pCoherCharIn[i] & 0x7F;
- if (pdx->dwInBuffPut >= INBUF_SZ)
- pdx->dwInBuffPut = 0;
- }
-
- if ((pdx->dwNumInput + nGot) <= INBUF_SZ)
- pdx->dwNumInput += nGot; /* Adjust the buffer count accordingly */
- } else
- dev_dbg(&pdx->interface->dev, "%s: read ZLP\n",
- __func__);
- }
- }
-
- pdx->bReadCharsPending = false; /* No longer have a pending read */
- spin_unlock(&pdx->charInLock); /* already at irq level */
-
- Allowi(pdx); /* see if we can do the next one */
-}
-
-/****************************************************************************
-** 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 Allowi(DEVICE_EXTENSION *pdx)
-{
- int iReturn = U14ERR_NOERROR;
- unsigned long flags;
- spin_lock_irqsave(&pdx->charInLock, flags); /* can be called in multiple contexts */
-
- /* 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 (!pdx->bInDrawDown && /* stop input if */
- !pdx->bReadCharsPending && /* If no read request outstanding */
- (pdx->dwNumInput < (INBUF_SZ / 2)) && /* and there is some space */
- (pdx->dwDMAFlag == MODE_CHAR) && /* not doing any DMA */
- (!pdx->bXFerWaiting) && /* no xfer waiting to start */
- (CanAcceptIoRequests(pdx))) { /* and activity is generally OK */
- /* then off we go */
- unsigned int nMax = INBUF_SZ - pdx->dwNumInput; /* max we could read */
- int nPipe = pdx->nPipes == 4 ? 1 : 0; /* The pipe number to use */
-
- dev_dbg(&pdx->interface->dev, "%s: %d chars in input buffer\n",
- __func__, pdx->dwNumInput);
-
- usb_fill_int_urb(pdx->pUrbCharIn, pdx->udev,
- usb_rcvintpipe(pdx->udev, pdx->epAddr[nPipe]),
- pdx->pCoherCharIn, nMax, ced_readchar_callback,
- pdx, pdx->bInterval);
- pdx->pUrbCharIn->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* short xfers are OK by default */
- usb_anchor_urb(pdx->pUrbCharIn, &pdx->submitted); /* in case we need to kill it */
- iReturn = usb_submit_urb(pdx->pUrbCharIn, GFP_ATOMIC);
- if (iReturn) {
- usb_unanchor_urb(pdx->pUrbCharIn); /* remove from list of active Urbs */
- pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
- dev_err(&pdx->interface->dev,
- "%s: submit urb failed: %d\n",
- __func__, iReturn);
- } else
- pdx->bReadCharsPending = true; /* Flag that we are active here */
- }
-
- spin_unlock_irqrestore(&pdx->charInLock, flags);
-
- return iReturn;
-
-}
-
-/*****************************************************************************
-** 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 pdx pointer
-** ulArg 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 ulArg)
-{
- int err = 0;
- DEVICE_EXTENSION *pdx = file->private_data;
- if (!CanAcceptIoRequests(pdx)) /* 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... */
- err = !access_ok(VERIFY_WRITE, (void __user *)ulArg, _IOC_SIZE(cmd)); /* is kernel write */
- else if (_IOC_DIR(cmd) & _IOC_WRITE) /* and write from point of view of user... */
- err = !access_ok(VERIFY_READ, (void __user *)ulArg, _IOC_SIZE(cmd)); /* is kernel read */
- if (err)
- return -EFAULT;
-
- switch (_IOC_NR(cmd)) {
- case _IOC_NR(IOCTL_CED_SENDSTRING(0)):
- return SendString(pdx, (const char __user *)ulArg,
- _IOC_SIZE(cmd));
-
- case _IOC_NR(IOCTL_CED_RESET1401):
- return Reset1401(pdx);
-
- case _IOC_NR(IOCTL_CED_GETCHAR):
- return GetChar(pdx);
-
- case _IOC_NR(IOCTL_CED_SENDCHAR):
- return SendChar(pdx, (char)ulArg);
-
- case _IOC_NR(IOCTL_CED_STAT1401):
- return Stat1401(pdx);
-
- case _IOC_NR(IOCTL_CED_LINECOUNT):
- return LineCount(pdx);
-
- case _IOC_NR(IOCTL_CED_GETSTRING(0)):
- return GetString(pdx, (char __user *)ulArg, _IOC_SIZE(cmd));
-
- case _IOC_NR(IOCTL_CED_SETTRANSFER):
- return SetTransfer(pdx, (struct transfer_area_desc __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_UNSETTRANSFER):
- return UnsetTransfer(pdx, (int)ulArg);
-
- case _IOC_NR(IOCTL_CED_SETEVENT):
- return SetEvent(pdx, (struct transfer_event __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE):
- return GetOutBufSpace(pdx);
-
- case _IOC_NR(IOCTL_CED_GETBASEADDRESS):
- return -1;
-
- case _IOC_NR(IOCTL_CED_GETDRIVERREVISION):
- return (2 << 24) | (DRIVERMAJREV << 16) | DRIVERMINREV; /* USB | MAJOR | MINOR */
-
- case _IOC_NR(IOCTL_CED_GETTRANSFER):
- return GetTransfer(pdx, (TGET_TX_BLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_KILLIO1401):
- return KillIO1401(pdx);
-
- case _IOC_NR(IOCTL_CED_STATEOF1401):
- return StateOf1401(pdx);
-
- case _IOC_NR(IOCTL_CED_GRAB1401):
- case _IOC_NR(IOCTL_CED_FREE1401):
- return U14ERR_NOERROR;
-
- case _IOC_NR(IOCTL_CED_STARTSELFTEST):
- return StartSelfTest(pdx);
-
- case _IOC_NR(IOCTL_CED_CHECKSELFTEST):
- return CheckSelfTest(pdx, (TGET_SELFTEST __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_TYPEOF1401):
- return TypeOf1401(pdx);
-
- case _IOC_NR(IOCTL_CED_TRANSFERFLAGS):
- return TransferFlags(pdx);
-
- case _IOC_NR(IOCTL_CED_DBGPEEK):
- return DbgPeek(pdx, (TDBGBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_DBGPOKE):
- return DbgPoke(pdx, (TDBGBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_DBGRAMPDATA):
- return DbgRampData(pdx, (TDBGBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_DBGRAMPADDR):
- return DbgRampAddr(pdx, (TDBGBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_DBGGETDATA):
- return DbgGetData(pdx, (TDBGBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_DBGSTOPLOOP):
- return DbgStopLoop(pdx);
-
- case _IOC_NR(IOCTL_CED_FULLRESET):
- pdx->bForceReset = true; /* Set a flag for a full reset */
- break;
-
- case _IOC_NR(IOCTL_CED_SETCIRCULAR):
- return SetCircular(pdx, (struct transfer_area_desc __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_GETCIRCBLOCK):
- return GetCircBlock(pdx, (TCIRCBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_FREECIRCBLOCK):
- return FreeCircBlock(pdx, (TCIRCBLOCK __user *) ulArg);
-
- case _IOC_NR(IOCTL_CED_WAITEVENT):
- return WaitEvent(pdx, (int)(ulArg & 0xff), (int)(ulArg >> 8));
-
- case _IOC_NR(IOCTL_CED_TESTEVENT):
- return TestEvent(pdx, (int)ulArg);
-
- 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 DEVICE_EXTENSION. */
-static int ced_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- DEVICE_EXTENSION *pdx;
- 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 */
- pdx = kzalloc(sizeof(*pdx), GFP_KERNEL);
- if (!pdx)
- goto error;
-
- for (i = 0; i < MAX_TRANSAREAS; ++i) { /* Initialise the wait queues */
- init_waitqueue_head(&pdx->rTransDef[i].wqEvent);
- }
-
- /* Put initialises for our stuff here. Note that all of *pdx is zero, so */
- /* no need to explicitly zero it. */
- spin_lock_init(&pdx->charOutLock);
- spin_lock_init(&pdx->charInLock);
- spin_lock_init(&pdx->stagedLock);
-
- /* Initialises from the skeleton stuff */
- kref_init(&pdx->kref);
- mutex_init(&pdx->io_mutex);
- spin_lock_init(&pdx->err_lock);
- init_usb_anchor(&pdx->submitted);
-
- pdx->udev = usb_get_dev(interface_to_usbdev(interface));
- pdx->interface = interface;
-
- /* Attempt to identify the device */
- bcdDevice = pdx->udev->descriptor.bcdDevice;
- i = (bcdDevice >> 8);
- if (i == 0)
- pdx->s1401Type = TYPEU1401;
- else if ((i >= 1) && (i <= 23))
- pdx->s1401Type = 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;
- pdx->nPipes = iface_desc->desc.bNumEndpoints;
- dev_info(&interface->dev, "1401Type=%d with %d End Points\n",
- pdx->s1401Type, pdx->nPipes);
- if ((pdx->nPipes < 3) || (pdx->nPipes > 4))
- goto error;
-
- /* Allocate the URBs we hold for performing transfers */
- pdx->pUrbCharOut = usb_alloc_urb(0, GFP_KERNEL); /* character output URB */
- pdx->pUrbCharIn = usb_alloc_urb(0, GFP_KERNEL); /* character input URB */
- pdx->pStagedUrb = usb_alloc_urb(0, GFP_KERNEL); /* block transfer URB */
- if (!pdx->pUrbCharOut || !pdx->pUrbCharIn || !pdx->pStagedUrb) {
- dev_err(&interface->dev, "%s: URB alloc failed\n", __func__);
- goto error;
- }
-
- pdx->pCoherStagedIO =
- usb_alloc_coherent(pdx->udev, STAGED_SZ, GFP_KERNEL,
- &pdx->pStagedUrb->transfer_dma);
- pdx->pCoherCharOut =
- usb_alloc_coherent(pdx->udev, OUTBUF_SZ, GFP_KERNEL,
- &pdx->pUrbCharOut->transfer_dma);
- pdx->pCoherCharIn =
- usb_alloc_coherent(pdx->udev, INBUF_SZ, GFP_KERNEL,
- &pdx->pUrbCharIn->transfer_dma);
- if (!pdx->pCoherCharOut || !pdx->pCoherCharIn || !pdx->pCoherStagedIO) {
- dev_err(&interface->dev, "%s: Coherent buffer alloc failed\n",
- __func__);
- goto error;
- }
-
- for (i = 0; i < pdx->nPipes; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- pdx->epAddr[i] = endpoint->bEndpointAddress;
- dev_info(&interface->dev, "Pipe %d, ep address %02x\n",
- i, pdx->epAddr[i]);
- if (((pdx->nPipes == 3) && (i == 0)) || /* if char input end point */
- ((pdx->nPipes == 4) && (i == 1))) {
- pdx->bInterval = endpoint->bInterval; /* save the endpoint interrupt interval */
- dev_info(&interface->dev, "Pipe %d, bInterval = %d\n",
- i, pdx->bInterval);
- }
- /* Detect USB2 by checking last ep size (64 if USB1) */
- if (i == pdx->nPipes - 1) { /* if this is the last ep (bulk) */
- pdx->bIsUSB2 =
- le16_to_cpu(endpoint->wMaxPacketSize) > 64;
- dev_info(&pdx->interface->dev, "USB%d\n",
- pdx->bIsUSB2 + 1);
- }
- }
-
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, pdx);
-
- /* 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 (pdx)
- kref_put(&pdx->kref, ced_delete); /* frees allocated memory */
- return retval;
-}
-
-static void ced_disconnect(struct usb_interface *interface)
-{
- DEVICE_EXTENSION *pdx = usb_get_intfdata(interface);
- int minor = interface->minor;
- int i;
-
- usb_set_intfdata(interface, NULL); /* remove the pdx from the interface */
- usb_deregister_dev(interface, &ced_class); /* give back our minor device number */
-
- mutex_lock(&pdx->io_mutex); /* stop more I/O starting while... */
- ced_draw_down(pdx); /* ...wait for then kill any io */
- for (i = 0; i < MAX_TRANSAREAS; ++i) {
- int iErr = ClearArea(pdx, i); /* ...release any used memory */
- if (iErr == U14ERR_UNLOCKFAIL)
- dev_err(&pdx->interface->dev, "%s: Area %d was in used\n",
- __func__, i);
- }
- pdx->interface = NULL; /* ...we kill off link to interface */
- mutex_unlock(&pdx->io_mutex);
-
- usb_kill_anchored_urbs(&pdx->submitted);
-
- kref_put(&pdx->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(DEVICE_EXTENSION *pdx)
-{
- int time;
- dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
-
- pdx->bInDrawDown = true;
- time = usb_wait_anchor_empty_timeout(&pdx->submitted, 3000);
- if (!time) { /* if we timed out we kill the urbs */
- usb_kill_anchored_urbs(&pdx->submitted);
- dev_err(&pdx->interface->dev, "%s: timed out\n", __func__);
- }
- pdx->bInDrawDown = false;
-}
-
-static int ced_suspend(struct usb_interface *intf, pm_message_t message)
-{
- DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- if (!pdx)
- return 0;
- ced_draw_down(pdx);
-
- dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
- return 0;
-}
-
-static int ced_resume(struct usb_interface *intf)
-{
- DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- if (!pdx)
- return 0;
- dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
- return 0;
-}
-
-static int ced_pre_reset(struct usb_interface *intf)
-{
- DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- dev_dbg(&pdx->interface->dev, "%s\n", __func__);
- mutex_lock(&pdx->io_mutex);
- ced_draw_down(pdx);
- return 0;
-}
-
-static int ced_post_reset(struct usb_interface *intf)
-{
- DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- dev_dbg(&pdx->interface->dev, "%s\n", __func__);
-
- /* we are sure no URBs are active - no locking needed */
- pdx->errors = -EPIPE;
- mutex_unlock(&pdx->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");