diff options
Diffstat (limited to 'drivers/staging/ced1401/usb1401.c')
-rw-r--r-- | drivers/staging/ced1401/usb1401.c | 1582 |
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"); |