mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-30 05:36:40 +07:00
Staging: rspiusb: remove the driver
No one cares, it's a custom userspace interface, and the code hasn't built in a long time. So remove it. Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
a8fcffbde4
commit
ffac040c05
@ -85,8 +85,6 @@ source "drivers/staging/rtl8192su/Kconfig"
|
|||||||
|
|
||||||
source "drivers/staging/rtl8192e/Kconfig"
|
source "drivers/staging/rtl8192e/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/rspiusb/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/staging/mimio/Kconfig"
|
source "drivers/staging/mimio/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/frontier/Kconfig"
|
source "drivers/staging/frontier/Kconfig"
|
||||||
|
@ -25,7 +25,6 @@ obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/
|
|||||||
obj-$(CONFIG_RTL8187SE) += rtl8187se/
|
obj-$(CONFIG_RTL8187SE) += rtl8187se/
|
||||||
obj-$(CONFIG_RTL8192SU) += rtl8192su/
|
obj-$(CONFIG_RTL8192SU) += rtl8192su/
|
||||||
obj-$(CONFIG_RTL8192E) += rtl8192e/
|
obj-$(CONFIG_RTL8192E) += rtl8192e/
|
||||||
obj-$(CONFIG_USB_RSPI) += rspiusb/
|
|
||||||
obj-$(CONFIG_INPUT_MIMIO) += mimio/
|
obj-$(CONFIG_INPUT_MIMIO) += mimio/
|
||||||
obj-$(CONFIG_TRANZPORT) += frontier/
|
obj-$(CONFIG_TRANZPORT) += frontier/
|
||||||
obj-$(CONFIG_ANDROID) += android/
|
obj-$(CONFIG_ANDROID) += android/
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
config USB_RSPI
|
|
||||||
tristate "Princeton Instruments USB camera support"
|
|
||||||
default n
|
|
||||||
depends on USB && BROKEN
|
|
||||||
help
|
|
||||||
This driver is for the Princeton Instruments USB camera device.
|
|
@ -1 +0,0 @@
|
|||||||
obj-$(CONFIG_USB_RSPI) += rspiusb.o
|
|
@ -1,22 +0,0 @@
|
|||||||
This driver is for the Princeton Instruments USB camera.
|
|
||||||
|
|
||||||
It needs lots of work to get it into the main drivers/usb/ subdirectory:
|
|
||||||
|
|
||||||
Any patches to do any of the following changes are greatly appreciated:
|
|
||||||
|
|
||||||
- make checkpatch.pl clean
|
|
||||||
- coding style fixups (typedefs, etc.)
|
|
||||||
- get it to build properly
|
|
||||||
- audit ioctls
|
|
||||||
- remove ioctls if possible
|
|
||||||
- assign proper minor number
|
|
||||||
- remove dbg() macro
|
|
||||||
- lots of general cleanups
|
|
||||||
- review locking
|
|
||||||
|
|
||||||
Please send patches to:
|
|
||||||
Greg Kroah-Hartman <gregkh@suse.de>
|
|
||||||
and CC:
|
|
||||||
Judd Montgomery <judd@jpilot.org>
|
|
||||||
Jeff Frontz <jeff.frontz@gmail.com>
|
|
||||||
as they have this device and can test any needed changes.
|
|
@ -1,929 +0,0 @@
|
|||||||
/*
|
|
||||||
* rspiusb.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2005, 2006 Princeton Instruments
|
|
||||||
*
|
|
||||||
* 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 version 2 of the License
|
|
||||||
*
|
|
||||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/smp_lock.h>
|
|
||||||
#include <linux/completion.h>
|
|
||||||
#include <linux/scatterlist.h>
|
|
||||||
#include <linux/usb.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/pagemap.h>
|
|
||||||
#include <linux/ioctl.h>
|
|
||||||
#include "rspiusb.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_DEBUG
|
|
||||||
static int debug = 1;
|
|
||||||
#else
|
|
||||||
static int debug;
|
|
||||||
#endif
|
|
||||||
/* Use our own dbg macro */
|
|
||||||
#undef dbg
|
|
||||||
#define dbg(format, arg...) \
|
|
||||||
do { \
|
|
||||||
if (debug) \
|
|
||||||
printk(KERN_DEBUG __FILE__ ": " format "\n" , ##arg); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Version Information */
|
|
||||||
#define DRIVER_VERSION "V1.0.1"
|
|
||||||
#define DRIVER_AUTHOR "Princeton Instruments"
|
|
||||||
#define DRIVER_DESC "PI USB2.0 Device Driver for Linux"
|
|
||||||
|
|
||||||
/* Define these values to match your devices */
|
|
||||||
#define VENDOR_ID 0x0BD7
|
|
||||||
#define ST133_PID 0xA010
|
|
||||||
#define PIXIS_PID 0xA026
|
|
||||||
|
|
||||||
/* Get a minor range for your devices from the usb maintainer */
|
|
||||||
#ifdef CONFIG_USB_DYNAMIC_MINORS
|
|
||||||
#define PIUSB_MINOR_BASE 0
|
|
||||||
#else
|
|
||||||
#define PIUSB_MINOR_BASE 192
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* prevent races between open() and disconnect() */
|
|
||||||
static DECLARE_MUTEX(disconnect_sem);
|
|
||||||
|
|
||||||
/* Structure to hold all of our device specific stuff */
|
|
||||||
struct device_extension {
|
|
||||||
struct usb_device *udev; /* save off the usb device pointer */
|
|
||||||
struct usb_interface *interface; /* the interface for this device */
|
|
||||||
unsigned char minor; /* the starting minor number
|
|
||||||
* for this device
|
|
||||||
*/
|
|
||||||
size_t bulk_in_size_returned;
|
|
||||||
int bulk_in_byte_trk;
|
|
||||||
struct urb ***PixelUrb;
|
|
||||||
int frameIdx;
|
|
||||||
int urbIdx;
|
|
||||||
unsigned int *maplist_numPagesMapped;
|
|
||||||
int open; /* if the port is open or not */
|
|
||||||
int present; /* if the device is not disconnected */
|
|
||||||
int userBufMapped; /* has the user buffer been mapped ? */
|
|
||||||
struct scatterlist **sgl; /* scatter-gather list for user buffer */
|
|
||||||
unsigned int *sgEntries;
|
|
||||||
struct kref kref;
|
|
||||||
int gotPixelData;
|
|
||||||
int pendingWrite;
|
|
||||||
char **pendedPixelUrbs;
|
|
||||||
int iama; /* PIXIS or ST133 */
|
|
||||||
int num_frames; /* the number of frames that will fit
|
|
||||||
* in the user buffer
|
|
||||||
*/
|
|
||||||
int active_frame;
|
|
||||||
unsigned long frameSize;
|
|
||||||
struct semaphore sem;
|
|
||||||
unsigned int hEP[8]; /* FX2 specific endpoints */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define to_pi_dev(d) container_of(d, struct device_extension, kref)
|
|
||||||
|
|
||||||
/* Prototypes */
|
|
||||||
static int MapUserBuffer(struct ioctl_struct *, struct device_extension *);
|
|
||||||
static int UnMapUserBuffer(struct device_extension *);
|
|
||||||
static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|
||||||
unsigned long arg);
|
|
||||||
static int piusb_output(struct ioctl_struct *, unsigned char *, int,
|
|
||||||
struct device_extension *);
|
|
||||||
static struct usb_driver piusb_driver;
|
|
||||||
|
|
||||||
/* table of devices that work with this driver */
|
|
||||||
static struct usb_device_id pi_device_table[] = {
|
|
||||||
{USB_DEVICE(VENDOR_ID, ST133_PID)},
|
|
||||||
{USB_DEVICE(VENDOR_ID, PIXIS_PID)},
|
|
||||||
{0, } /* Terminating entry */
|
|
||||||
};
|
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(usb, pi_device_table);
|
|
||||||
|
|
||||||
static int lastErr;
|
|
||||||
static int errCnt;
|
|
||||||
|
|
||||||
static void piusb_delete(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx = to_pi_dev(kref);
|
|
||||||
|
|
||||||
dev_dbg(&pdx->udev->dev, "%s\n", __func__);
|
|
||||||
usb_put_dev(pdx->udev);
|
|
||||||
kfree(pdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int piusb_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx = NULL;
|
|
||||||
struct usb_interface *interface;
|
|
||||||
int subminor;
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
dbg("Piusb_Open()");
|
|
||||||
subminor = iminor(inode);
|
|
||||||
interface = usb_find_interface(&piusb_driver, subminor);
|
|
||||||
if (!interface) {
|
|
||||||
printk(KERN_ERR "%s - error, can't find device for minor %d\n",
|
|
||||||
__func__, subminor);
|
|
||||||
retval = -ENODEV;
|
|
||||||
goto exit_no_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdx = usb_get_intfdata(interface);
|
|
||||||
if (!pdx) {
|
|
||||||
retval = -ENODEV;
|
|
||||||
goto exit_no_device;
|
|
||||||
}
|
|
||||||
dbg("Alternate Setting = %d", interface->num_altsetting);
|
|
||||||
|
|
||||||
pdx->bulk_in_size_returned = 0;
|
|
||||||
pdx->bulk_in_byte_trk = 0;
|
|
||||||
pdx->PixelUrb = NULL;
|
|
||||||
pdx->frameIdx = 0;
|
|
||||||
pdx->urbIdx = 0;
|
|
||||||
pdx->maplist_numPagesMapped = NULL;
|
|
||||||
pdx->userBufMapped = 0;
|
|
||||||
pdx->sgl = NULL;
|
|
||||||
pdx->sgEntries = NULL;
|
|
||||||
pdx->gotPixelData = 0;
|
|
||||||
pdx->pendingWrite = 0;
|
|
||||||
pdx->pendedPixelUrbs = NULL;
|
|
||||||
pdx->num_frames = 0;
|
|
||||||
pdx->active_frame = 0;
|
|
||||||
pdx->frameSize = 0;
|
|
||||||
|
|
||||||
/* increment our usage count for the device */
|
|
||||||
kref_get(&pdx->kref);
|
|
||||||
|
|
||||||
/* save our object in the file's private structure */
|
|
||||||
file->private_data = pdx;
|
|
||||||
|
|
||||||
exit_no_device:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int piusb_release(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx;
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
dbg("Piusb_Release()");
|
|
||||||
pdx = (struct device_extension *)file->private_data;
|
|
||||||
if (pdx == NULL) {
|
|
||||||
dbg("%s - object is NULL", __func__);
|
|
||||||
retval = -ENODEV;
|
|
||||||
goto object_null;
|
|
||||||
}
|
|
||||||
/* decrement the count on our device */
|
|
||||||
kref_put(&pdx->kref, piusb_delete);
|
|
||||||
|
|
||||||
object_null:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pixis_io(struct ioctl_struct *ctrl, struct device_extension *pdx,
|
|
||||||
struct ioctl_struct *arg)
|
|
||||||
{
|
|
||||||
unsigned int numToRead = 0;
|
|
||||||
unsigned int totalRead = 0;
|
|
||||||
unsigned char *uBuf;
|
|
||||||
int numbytes;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
uBuf = kmalloc(ctrl->numbytes, GFP_KERNEL);
|
|
||||||
if (!uBuf) {
|
|
||||||
dbg("Alloc for uBuf failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
numbytes = (int) ctrl->numbytes;
|
|
||||||
numToRead = (unsigned int) ctrl->numbytes;
|
|
||||||
dbg("numbytes to read = %d", numbytes);
|
|
||||||
dbg("endpoint # %d", ctrl->endpoint);
|
|
||||||
|
|
||||||
if (copy_from_user(uBuf, ctrl->pData, numbytes)) {
|
|
||||||
dbg("copying ctrl->pData to dummyBuf failed");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl->endpoint],
|
|
||||||
(uBuf + totalRead),
|
|
||||||
/* EP0 can only handle 64 bytes at a time */
|
|
||||||
(numToRead > 64) ? 64 : numToRead,
|
|
||||||
&numbytes, HZ * 10);
|
|
||||||
if (i) {
|
|
||||||
dbg("CMD = %s, Address = 0x%02X",
|
|
||||||
((uBuf[3] == 0x02) ? "WRITE" : "READ"),
|
|
||||||
uBuf[1]);
|
|
||||||
dbg("Number of bytes Attempted to read = %d",
|
|
||||||
(int)ctrl->numbytes);
|
|
||||||
dbg("Blocking ReadI/O Failed with status %d", i);
|
|
||||||
kfree(uBuf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
dbg("Pixis EP0 Read %d bytes", numbytes);
|
|
||||||
totalRead += numbytes;
|
|
||||||
numToRead -= numbytes;
|
|
||||||
} while (numToRead);
|
|
||||||
|
|
||||||
memcpy(ctrl->pData, uBuf, totalRead);
|
|
||||||
dbg("Total Bytes Read from PIXIS EP0 = %d", totalRead);
|
|
||||||
ctrl->numbytes = totalRead;
|
|
||||||
|
|
||||||
if (copy_to_user(arg, ctrl, sizeof(struct ioctl_struct)))
|
|
||||||
dbg("copy_to_user failed in IORB");
|
|
||||||
|
|
||||||
kfree(uBuf);
|
|
||||||
return ctrl->numbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pixel_data(struct ioctl_struct *ctrl, struct device_extension *pdx)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!pdx->gotPixelData)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pdx->gotPixelData = 0;
|
|
||||||
ctrl->numbytes = pdx->bulk_in_size_returned;
|
|
||||||
pdx->bulk_in_size_returned -= pdx->frameSize;
|
|
||||||
|
|
||||||
for (i = 0; i < pdx->maplist_numPagesMapped[pdx->active_frame]; i++)
|
|
||||||
SetPageDirty(sg_page(&pdx->sgl[pdx->active_frame][i]));
|
|
||||||
|
|
||||||
pdx->active_frame = ((pdx->active_frame + 1) % pdx->num_frames);
|
|
||||||
|
|
||||||
return ctrl->numbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* piusb_ioctl
|
|
||||||
*/
|
|
||||||
static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|
||||||
unsigned long arg)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx;
|
|
||||||
char dummyCtlBuf[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
unsigned long devRB = 0;
|
|
||||||
int err = 0;
|
|
||||||
int retval = 0;
|
|
||||||
struct ioctl_struct ctrl;
|
|
||||||
unsigned short controlData = 0;
|
|
||||||
|
|
||||||
pdx = (struct device_extension *)file->private_data;
|
|
||||||
/* verify that the device wasn't unplugged */
|
|
||||||
if (!pdx->present) {
|
|
||||||
dbg("No Device Present\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
/* fill in your device specific stuff here */
|
|
||||||
if (_IOC_DIR(cmd) & _IOC_READ)
|
|
||||||
err = !access_ok(VERIFY_WRITE, (void __user *)arg,
|
|
||||||
_IOC_SIZE(cmd));
|
|
||||||
else if (_IOC_DIR(cmd) & _IOC_WRITE)
|
|
||||||
err = !access_ok(VERIFY_READ, (void __user *)arg,
|
|
||||||
_IOC_SIZE(cmd));
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdx->udev->dev, "return with error = %d\n", err);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
switch (cmd) {
|
|
||||||
case PIUSB_GETVNDCMD:
|
|
||||||
if (__copy_from_user
|
|
||||||
(&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) {
|
|
||||||
dev_err(&pdx->udev->dev, "copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
dbg("%s %x\n", "Get Vendor Command = ", ctrl.cmd);
|
|
||||||
retval =
|
|
||||||
usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0),
|
|
||||||
ctrl.cmd, USB_DIR_IN, 0, 0, &devRB,
|
|
||||||
ctrl.numbytes, HZ * 10);
|
|
||||||
if (ctrl.cmd == 0xF1) {
|
|
||||||
dbg("FW Version returned from HW = %ld.%ld",
|
|
||||||
(devRB >> 8), (devRB & 0xFF));
|
|
||||||
}
|
|
||||||
if (retval >= 0)
|
|
||||||
retval = (int)devRB;
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
case PIUSB_SETVNDCMD:
|
|
||||||
if (__copy_from_user
|
|
||||||
(&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) {
|
|
||||||
dev_err(&pdx->udev->dev, "copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
/* dbg( "%s %x", "Set Vendor Command = ",ctrl.cmd ); */
|
|
||||||
controlData = ctrl.pData[0];
|
|
||||||
controlData |= (ctrl.pData[1] << 8);
|
|
||||||
/* dbg( "%s %d", "Vendor Data =",controlData ); */
|
|
||||||
retval = usb_control_msg(pdx->udev,
|
|
||||||
usb_sndctrlpipe(pdx->udev, 0),
|
|
||||||
ctrl.cmd,
|
|
||||||
(USB_DIR_OUT | USB_TYPE_VENDOR
|
|
||||||
/* | USB_RECIP_ENDPOINT */),
|
|
||||||
controlData, 0,
|
|
||||||
&dummyCtlBuf, ctrl.numbytes, HZ * 10);
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
case PIUSB_ISHIGHSPEED:
|
|
||||||
return ((pdx->udev->speed == USB_SPEED_HIGH) ? 1 : 0);
|
|
||||||
|
|
||||||
case PIUSB_WRITEPIPE:
|
|
||||||
if (__copy_from_user(&ctrl, (void __user *)arg, _IOC_SIZE(cmd))) {
|
|
||||||
dev_err(&pdx->udev->dev,
|
|
||||||
"copy_from_user WRITE_DUMMY failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (!access_ok(VERIFY_READ, ctrl.pData, ctrl.numbytes)) {
|
|
||||||
dbg("can't access pData");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
piusb_output(&ctrl, ctrl.pData /* uBuf */, ctrl.numbytes, pdx);
|
|
||||||
return ctrl.numbytes;
|
|
||||||
|
|
||||||
case PIUSB_USERBUFFER:
|
|
||||||
if (__copy_from_user
|
|
||||||
(&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) {
|
|
||||||
dev_err(&pdx->udev->dev, "copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
return MapUserBuffer((struct ioctl_struct *) &ctrl, pdx);
|
|
||||||
|
|
||||||
case PIUSB_UNMAP_USERBUFFER:
|
|
||||||
retval = UnMapUserBuffer(pdx);
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
case PIUSB_READPIPE:
|
|
||||||
if (__copy_from_user(&ctrl, (void __user *)arg,
|
|
||||||
sizeof(struct ioctl_struct))) {
|
|
||||||
dev_err(&pdx->udev->dev, "copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
if (((0 == ctrl.endpoint) && (PIXIS_PID == pdx->iama)) ||
|
|
||||||
(1 == ctrl.endpoint) || /* ST133IO */
|
|
||||||
(4 == ctrl.endpoint)) /* PIXIS IO */
|
|
||||||
return pixis_io(&ctrl, pdx,
|
|
||||||
(struct ioctl_struct *)arg);
|
|
||||||
else if ((0 == ctrl.endpoint) || /* ST133 Pixel Data */
|
|
||||||
(2 == ctrl.endpoint) || /* PIXIS Ping */
|
|
||||||
(3 == ctrl.endpoint)) /* PIXIS Pong */
|
|
||||||
return pixel_data(&ctrl, pdx);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PIUSB_WHATCAMERA:
|
|
||||||
return pdx->iama;
|
|
||||||
|
|
||||||
case PIUSB_SETFRAMESIZE:
|
|
||||||
dbg("PIUSB_SETFRAMESIZE");
|
|
||||||
if (__copy_from_user
|
|
||||||
(&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) {
|
|
||||||
dev_err(&pdx->udev->dev, "copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
pdx->frameSize = ctrl.numbytes;
|
|
||||||
pdx->num_frames = ctrl.numFrames;
|
|
||||||
if (!pdx->sgl)
|
|
||||||
pdx->sgl =
|
|
||||||
kmalloc(sizeof(struct scatterlist *) *
|
|
||||||
pdx->num_frames, GFP_KERNEL);
|
|
||||||
if (!pdx->sgEntries)
|
|
||||||
pdx->sgEntries =
|
|
||||||
kmalloc(sizeof(unsigned int) * pdx->num_frames,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!pdx->PixelUrb)
|
|
||||||
pdx->PixelUrb =
|
|
||||||
kmalloc(sizeof(struct urb **) * pdx->num_frames,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!pdx->maplist_numPagesMapped)
|
|
||||||
pdx->maplist_numPagesMapped =
|
|
||||||
vmalloc(sizeof(unsigned int) * pdx->num_frames);
|
|
||||||
if (!pdx->pendedPixelUrbs)
|
|
||||||
pdx->pendedPixelUrbs =
|
|
||||||
kmalloc(sizeof(char *) * pdx->num_frames,
|
|
||||||
GFP_KERNEL);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
dbg("%s\n", "No IOCTL found");
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
/* return that we did not understand this ioctl call */
|
|
||||||
dbg("Returning -ENOTTY");
|
|
||||||
return -ENOTTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void piusb_write_bulk_callback(struct urb *urb)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx = urb->context;
|
|
||||||
int status = urb->status;
|
|
||||||
|
|
||||||
/* sync/async unlink faults aren't errors */
|
|
||||||
if (status && !(status == -ENOENT || status == -ECONNRESET))
|
|
||||||
dev_dbg(&urb->dev->dev,
|
|
||||||
"%s - nonzero write bulk status received: %d",
|
|
||||||
__func__, status);
|
|
||||||
|
|
||||||
pdx->pendingWrite = 0;
|
|
||||||
kfree(urb->transfer_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len,
|
|
||||||
struct device_extension *pdx)
|
|
||||||
{
|
|
||||||
struct urb *urb = NULL;
|
|
||||||
int err = 0;
|
|
||||||
unsigned char *kbuf = NULL;
|
|
||||||
|
|
||||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
||||||
if (urb != NULL) {
|
|
||||||
kbuf = kmalloc(len, GFP_KERNEL);
|
|
||||||
if (!kbuf) {
|
|
||||||
dev_err(&pdx->udev->dev, "buffer_alloc failed\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
if(__copy_from_user(kbuf, uBuf, len)) {
|
|
||||||
dev_err(&pdx->udev->dev, "__copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf,
|
|
||||||
len, piusb_write_bulk_callback, pdx);
|
|
||||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdx->udev->dev,
|
|
||||||
"WRITE ERROR:submit urb error = %d\n", err);
|
|
||||||
}
|
|
||||||
pdx->pendingWrite = 1;
|
|
||||||
usb_free_urb(urb);
|
|
||||||
}
|
|
||||||
return -EINPROGRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int UnMapUserBuffer(struct device_extension *pdx)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
int k = 0;
|
|
||||||
unsigned int epAddr;
|
|
||||||
|
|
||||||
for (k = 0; k < pdx->num_frames; k++) {
|
|
||||||
dbg("Killing Urbs for Frame %d", k);
|
|
||||||
for (i = 0; i < pdx->sgEntries[k]; i++) {
|
|
||||||
usb_kill_urb(pdx->PixelUrb[k][i]);
|
|
||||||
usb_free_urb(pdx->PixelUrb[k][i]);
|
|
||||||
pdx->pendedPixelUrbs[k][i] = 0;
|
|
||||||
}
|
|
||||||
dbg("Urb error count = %d", errCnt);
|
|
||||||
errCnt = 0;
|
|
||||||
dbg("Urbs free'd and Killed for Frame %d", k);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (k = 0; k < pdx->num_frames; k++) {
|
|
||||||
if (pdx->iama == PIXIS_PID)
|
|
||||||
/* which EP should we map this frame to ? */
|
|
||||||
/* PONG, odd frames: hEP[3] */
|
|
||||||
/* PING, even frames and zero hEP[2] */
|
|
||||||
epAddr = (k % 2) ? pdx->hEP[3] : pdx->hEP[2];
|
|
||||||
else
|
|
||||||
/* ST133 only has 1 endpoint for Pixel data transfer */
|
|
||||||
epAddr = pdx->hEP[0];
|
|
||||||
|
|
||||||
usb_buffer_unmap_sg(pdx->udev, epAddr, pdx->sgl[k],
|
|
||||||
pdx->maplist_numPagesMapped[k]);
|
|
||||||
for (i = 0; i < pdx->maplist_numPagesMapped[k]; i++)
|
|
||||||
page_cache_release(sg_page(&pdx->sgl[k][i]));
|
|
||||||
kfree(pdx->sgl[k]);
|
|
||||||
kfree(pdx->PixelUrb[k]);
|
|
||||||
kfree(pdx->pendedPixelUrbs[k]);
|
|
||||||
pdx->sgl[k] = NULL;
|
|
||||||
pdx->PixelUrb[k] = NULL;
|
|
||||||
pdx->pendedPixelUrbs[k] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(pdx->sgEntries);
|
|
||||||
vfree(pdx->maplist_numPagesMapped);
|
|
||||||
pdx->sgEntries = NULL;
|
|
||||||
pdx->maplist_numPagesMapped = NULL;
|
|
||||||
kfree(pdx->sgl);
|
|
||||||
kfree(pdx->pendedPixelUrbs);
|
|
||||||
kfree(pdx->PixelUrb);
|
|
||||||
pdx->sgl = NULL;
|
|
||||||
pdx->pendedPixelUrbs = NULL;
|
|
||||||
pdx->PixelUrb = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void piusb_readPIXEL_callback(struct urb *urb)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
struct device_extension *pdx = urb->context;
|
|
||||||
int status = urb->status;
|
|
||||||
|
|
||||||
if (status && !(status == -ENOENT || status == -ECONNRESET)) {
|
|
||||||
dbg("%s - nonzero read bulk status received: %d", __func__,
|
|
||||||
status);
|
|
||||||
dbg("Error in read EP2 callback");
|
|
||||||
dbg("FrameIndex = %d", pdx->frameIdx);
|
|
||||||
dbg("Bytes received before problem occurred = %d",
|
|
||||||
pdx->bulk_in_byte_trk);
|
|
||||||
dbg("Urb Idx = %d", pdx->urbIdx);
|
|
||||||
pdx->pendedPixelUrbs[pdx->frameIdx][pdx->urbIdx] = 0;
|
|
||||||
} else {
|
|
||||||
pdx->bulk_in_byte_trk += urb->actual_length;
|
|
||||||
i = usb_submit_urb(urb, GFP_ATOMIC); /* resubmit the URB */
|
|
||||||
if (i) {
|
|
||||||
errCnt++;
|
|
||||||
if (i != lastErr) {
|
|
||||||
dbg("submit urb in callback failed "
|
|
||||||
"with error code %d", i);
|
|
||||||
lastErr = i;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pdx->urbIdx++; /* point to next URB when we callback */
|
|
||||||
if (pdx->bulk_in_byte_trk >= pdx->frameSize) {
|
|
||||||
pdx->bulk_in_size_returned =
|
|
||||||
pdx->bulk_in_byte_trk;
|
|
||||||
pdx->bulk_in_byte_trk = 0;
|
|
||||||
pdx->gotPixelData = 1;
|
|
||||||
pdx->frameIdx =
|
|
||||||
((pdx->frameIdx +
|
|
||||||
1) % pdx->num_frames);
|
|
||||||
pdx->urbIdx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MapUserBuffer(
|
|
||||||
inputs:
|
|
||||||
struct ioctl_struct *io - structure containing user address,
|
|
||||||
frame #, and size
|
|
||||||
struct device_extension *pdx - the PIUSB device extension
|
|
||||||
|
|
||||||
returns:
|
|
||||||
int - status of the task
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
MapUserBuffer maps a buffer passed down through an ioctl.
|
|
||||||
The user buffer is Page Aligned by the app and then passed down.
|
|
||||||
The function get_free_pages(...) does the actual mapping of the buffer
|
|
||||||
from user space to kernel space.
|
|
||||||
From there a scatterlist is created from all the pages.
|
|
||||||
The next function called is to usb_buffer_map_sg which allocated
|
|
||||||
DMA addresses for each page, even coalescing them if possible.
|
|
||||||
The DMA address is placed in the scatterlist structure.
|
|
||||||
The function returns the number of DMA addresses.
|
|
||||||
This may or may not be equal to the number of pages that
|
|
||||||
the user buffer uses.
|
|
||||||
We then build an URB for each DMA address and then submit them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
int MapUserBuffer(unsigned long uaddr, unsigned long numbytes,
|
|
||||||
unsigned long frameInfo, struct device_extension *pdx)
|
|
||||||
*/
|
|
||||||
static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
|
|
||||||
{
|
|
||||||
unsigned long uaddr;
|
|
||||||
unsigned long numbytes;
|
|
||||||
int frameInfo; /* which frame we're mapping */
|
|
||||||
unsigned int epAddr = 0;
|
|
||||||
unsigned long count = 0;
|
|
||||||
int i = 0;
|
|
||||||
int k = 0;
|
|
||||||
int err = 0;
|
|
||||||
int ret;
|
|
||||||
struct page **maplist_p;
|
|
||||||
int numPagesRequired;
|
|
||||||
|
|
||||||
frameInfo = io->numFrames;
|
|
||||||
uaddr = (unsigned long)io->pData;
|
|
||||||
numbytes = io->numbytes;
|
|
||||||
|
|
||||||
if (pdx->iama == PIXIS_PID) {
|
|
||||||
/* which EP should we map this frame to ? */
|
|
||||||
/* PONG, odd frames: hEP[3] */
|
|
||||||
/* PING, even frames and zero hEP[2] */
|
|
||||||
epAddr = (frameInfo % 2) ? pdx->hEP[3] : pdx->hEP[2];
|
|
||||||
dbg("Pixis Frame #%d: EP=%d", frameInfo,
|
|
||||||
(epAddr == pdx->hEP[2]) ? 2 : 4);
|
|
||||||
} else { /* ST133 only has 1 endpoint for Pixel data transfer */
|
|
||||||
epAddr = pdx->hEP[0];
|
|
||||||
dbg("ST133 Frame #%d: EP=2", frameInfo);
|
|
||||||
}
|
|
||||||
count = numbytes;
|
|
||||||
dbg("UserAddress = 0x%08lX", uaddr);
|
|
||||||
dbg("numbytes = %d", (int)numbytes);
|
|
||||||
|
|
||||||
/* number of pages to map the entire user space DMA buffer */
|
|
||||||
numPagesRequired =
|
|
||||||
((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
|
|
||||||
dbg("Number of pages needed = %d", numPagesRequired);
|
|
||||||
maplist_p = vmalloc(numPagesRequired * sizeof(struct page *));
|
|
||||||
if (!maplist_p) {
|
|
||||||
dbg("Can't Allocate Memory for maplist_p");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* map the user buffer to kernel memory */
|
|
||||||
down_write(¤t->mm->mmap_sem);
|
|
||||||
pdx->maplist_numPagesMapped[frameInfo] = get_user_pages(current,
|
|
||||||
current->mm, (uaddr & PAGE_MASK), numPagesRequired,
|
|
||||||
WRITE, 0 /* Don't Force*/, maplist_p, NULL);
|
|
||||||
up_write(¤t->mm->mmap_sem);
|
|
||||||
dbg("Number of pages mapped = %d",
|
|
||||||
pdx->maplist_numPagesMapped[frameInfo]);
|
|
||||||
|
|
||||||
for (i = 0; i < pdx->maplist_numPagesMapped[frameInfo]; i++)
|
|
||||||
flush_dcache_page(maplist_p[i]);
|
|
||||||
if (!pdx->maplist_numPagesMapped[frameInfo]) {
|
|
||||||
dbg("get_user_pages() failed");
|
|
||||||
vfree(maplist_p);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* need to create a scatterlist that spans each frame
|
|
||||||
* that can fit into the mapped buffer
|
|
||||||
*/
|
|
||||||
pdx->sgl[frameInfo] =
|
|
||||||
kmalloc((pdx->maplist_numPagesMapped[frameInfo] *
|
|
||||||
sizeof(struct scatterlist)), GFP_ATOMIC);
|
|
||||||
if (!pdx->sgl[frameInfo]) {
|
|
||||||
vfree(maplist_p);
|
|
||||||
dbg("can't allocate mem for sgl");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
sg_assign_page(&pdx->sgl[frameInfo][0], maplist_p[0]);
|
|
||||||
pdx->sgl[frameInfo][0].offset = uaddr & ~PAGE_MASK;
|
|
||||||
if (pdx->maplist_numPagesMapped[frameInfo] > 1) {
|
|
||||||
pdx->sgl[frameInfo][0].length =
|
|
||||||
PAGE_SIZE - pdx->sgl[frameInfo][0].offset;
|
|
||||||
count -= pdx->sgl[frameInfo][0].length;
|
|
||||||
for (k = 1; k < pdx->maplist_numPagesMapped[frameInfo]; k++) {
|
|
||||||
pdx->sgl[frameInfo][k].offset = 0;
|
|
||||||
sg_assign_page(&pdx->sgl[frameInfo][k], maplist_p[k]);
|
|
||||||
pdx->sgl[frameInfo][k].length =
|
|
||||||
(count < PAGE_SIZE) ? count : PAGE_SIZE;
|
|
||||||
count -= PAGE_SIZE; /* example had PAGE_SIZE here */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pdx->sgl[frameInfo][0].length = count;
|
|
||||||
}
|
|
||||||
ret = usb_buffer_map_sg(pdx->udev, epAddr, pdx->sgl[frameInfo],
|
|
||||||
pdx->maplist_numPagesMapped[frameInfo]);
|
|
||||||
if (ret < 0) {
|
|
||||||
vfree(maplist_p);
|
|
||||||
dbg("usb_buffer_map_sg() failed");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdx->sgEntries[frameInfo] = ret;
|
|
||||||
|
|
||||||
dbg("number of sgEntries = %d", pdx->sgEntries[frameInfo]);
|
|
||||||
pdx->userBufMapped = 1;
|
|
||||||
vfree(maplist_p);
|
|
||||||
|
|
||||||
/* Create and Send the URB's for each s/g entry */
|
|
||||||
pdx->PixelUrb[frameInfo] =
|
|
||||||
kmalloc(pdx->sgEntries[frameInfo] * sizeof(struct urb *),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!pdx->PixelUrb[frameInfo]) {
|
|
||||||
dbg("Can't Allocate Memory for Urb");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
for (i = 0; i < pdx->sgEntries[frameInfo]; i++) {
|
|
||||||
/* 0 iso packets because we're using BULK transfers */
|
|
||||||
pdx->PixelUrb[frameInfo][i] = usb_alloc_urb(0, GFP_KERNEL);
|
|
||||||
usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i],
|
|
||||||
pdx->udev,
|
|
||||||
epAddr,
|
|
||||||
NULL, // non-DMA HC? buy a better hardware
|
|
||||||
sg_dma_len(&pdx->sgl[frameInfo][i]),
|
|
||||||
piusb_readPIXEL_callback, (void *)pdx);
|
|
||||||
pdx->PixelUrb[frameInfo][i]->transfer_dma =
|
|
||||||
sg_dma_address(&pdx->sgl[frameInfo][i]);
|
|
||||||
pdx->PixelUrb[frameInfo][i]->transfer_flags =
|
|
||||||
URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
|
|
||||||
}
|
|
||||||
/* only interrupt when last URB completes */
|
|
||||||
pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT;
|
|
||||||
pdx->pendedPixelUrbs[frameInfo] =
|
|
||||||
kmalloc((pdx->sgEntries[frameInfo] * sizeof(char)), GFP_KERNEL);
|
|
||||||
if (!pdx->pendedPixelUrbs[frameInfo])
|
|
||||||
dbg("Can't allocate Memory for pendedPixelUrbs");
|
|
||||||
for (i = 0; i < pdx->sgEntries[frameInfo]; i++) {
|
|
||||||
err = usb_submit_urb(pdx->PixelUrb[frameInfo][i], GFP_ATOMIC);
|
|
||||||
if (err) {
|
|
||||||
dbg("%s %d\n", "submit urb error =", err);
|
|
||||||
pdx->pendedPixelUrbs[frameInfo][i] = 0;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
pdx->pendedPixelUrbs[frameInfo][i] = 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations piusb_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.ioctl = piusb_ioctl,
|
|
||||||
.open = piusb_open,
|
|
||||||
.release = piusb_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct usb_class_driver piusb_class = {
|
|
||||||
.name = "usb/rspiusb%d",
|
|
||||||
.fops = &piusb_fops,
|
|
||||||
.minor_base = PIUSB_MINOR_BASE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* piusb_probe
|
|
||||||
*
|
|
||||||
* Called by the usb core when a new device is connected that it thinks
|
|
||||||
* this driver might be interested in.
|
|
||||||
*/
|
|
||||||
static int piusb_probe(struct usb_interface *interface,
|
|
||||||
const struct usb_device_id *id)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx = NULL;
|
|
||||||
struct usb_host_interface *iface_desc;
|
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
|
||||||
int i;
|
|
||||||
int retval = -ENOMEM;
|
|
||||||
|
|
||||||
dev_dbg(&interface->dev, "%s - Looking for PI USB Hardware", __func__);
|
|
||||||
|
|
||||||
pdx = kzalloc(sizeof(struct device_extension), GFP_KERNEL);
|
|
||||||
if (pdx == NULL) {
|
|
||||||
dev_err(&interface->dev, "Out of memory\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
kref_init(&pdx->kref);
|
|
||||||
pdx->udev = usb_get_dev(interface_to_usbdev(interface));
|
|
||||||
pdx->interface = interface;
|
|
||||||
iface_desc = interface->cur_altsetting;
|
|
||||||
|
|
||||||
/* See if the device offered us matches what we can accept */
|
|
||||||
if ((pdx->udev->descriptor.idVendor != VENDOR_ID)
|
|
||||||
|| ((pdx->udev->descriptor.idProduct != PIXIS_PID)
|
|
||||||
&& (pdx->udev->descriptor.idProduct != ST133_PID)))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
pdx->iama = pdx->udev->descriptor.idProduct;
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
if (pdx->udev->descriptor.idProduct == PIXIS_PID)
|
|
||||||
dbg("PIUSB:Pixis Camera Found");
|
|
||||||
else
|
|
||||||
dbg("PIUSB:ST133 USB Controller Found");
|
|
||||||
if (pdx->udev->speed == USB_SPEED_HIGH)
|
|
||||||
dbg("Highspeed(USB2.0) Device Attached");
|
|
||||||
else
|
|
||||||
dbg("Lowspeed (USB1.1) Device Attached");
|
|
||||||
|
|
||||||
dbg("NumEndpoints in Configuration: %d",
|
|
||||||
iface_desc->desc.bNumEndpoints);
|
|
||||||
}
|
|
||||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
|
||||||
endpoint = &iface_desc->endpoint[i].desc;
|
|
||||||
if (debug) {
|
|
||||||
dbg("Endpoint[%d]->bDescriptorType = %d", i,
|
|
||||||
endpoint->bDescriptorType);
|
|
||||||
dbg("Endpoint[%d]->bEndpointAddress = 0x%02X", i,
|
|
||||||
endpoint->bEndpointAddress);
|
|
||||||
dbg("Endpoint[%d]->bbmAttributes = %d", i,
|
|
||||||
endpoint->bmAttributes);
|
|
||||||
dbg("Endpoint[%d]->MaxPacketSize = %d\n", i,
|
|
||||||
endpoint->wMaxPacketSize);
|
|
||||||
}
|
|
||||||
if (usb_endpoint_xfer_bulk(endpoint)) {
|
|
||||||
if (usb_endpoint_dir_in(endpoint))
|
|
||||||
pdx->hEP[i] =
|
|
||||||
usb_rcvbulkpipe(pdx->udev,
|
|
||||||
endpoint->bEndpointAddress);
|
|
||||||
else
|
|
||||||
pdx->hEP[i] =
|
|
||||||
usb_sndbulkpipe(pdx->udev,
|
|
||||||
endpoint->bEndpointAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
usb_set_intfdata(interface, pdx);
|
|
||||||
retval = usb_register_dev(interface, &piusb_class);
|
|
||||||
if (retval) {
|
|
||||||
err("Not able to get a minor for this device.");
|
|
||||||
usb_set_intfdata(interface, NULL);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
pdx->present = 1;
|
|
||||||
|
|
||||||
/* we can register the device now, as it is ready */
|
|
||||||
pdx->minor = interface->minor;
|
|
||||||
/* let the user know what node this device is now attached to */
|
|
||||||
dbg("PI USB2.0 device now attached to piusb-%d", pdx->minor);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (pdx)
|
|
||||||
kref_put(&pdx->kref, piusb_delete);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* piusb_disconnect
|
|
||||||
*
|
|
||||||
* Called by the usb core when the device is removed from the system.
|
|
||||||
*
|
|
||||||
* This routine guarantees that the driver will not submit any more urbs
|
|
||||||
* by clearing pdx->udev. It is also supposed to terminate any currently
|
|
||||||
* active urbs. Unfortunately, usb_bulk_msg(), used in piusb_read(), does
|
|
||||||
* not provide any way to do this. But at least we can cancel an active
|
|
||||||
* write.
|
|
||||||
*/
|
|
||||||
static void piusb_disconnect(struct usb_interface *interface)
|
|
||||||
{
|
|
||||||
struct device_extension *pdx;
|
|
||||||
int minor = interface->minor;
|
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
|
|
||||||
pdx = usb_get_intfdata(interface);
|
|
||||||
usb_set_intfdata(interface, NULL);
|
|
||||||
|
|
||||||
/* give back our minor */
|
|
||||||
usb_deregister_dev(interface, &piusb_class);
|
|
||||||
|
|
||||||
unlock_kernel();
|
|
||||||
|
|
||||||
/* prevent device read, write and ioctl */
|
|
||||||
pdx->present = 0;
|
|
||||||
kref_put(&pdx->kref, piusb_delete);
|
|
||||||
dbg("PI USB2.0 device #%d now disconnected\n", minor);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct usb_driver piusb_driver = {
|
|
||||||
.name = "sub",
|
|
||||||
.probe = piusb_probe,
|
|
||||||
.disconnect = piusb_disconnect,
|
|
||||||
.id_table = pi_device_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* piusb_init
|
|
||||||
*/
|
|
||||||
static int __init piusb_init(void)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
lastErr = 0;
|
|
||||||
errCnt = 0;
|
|
||||||
|
|
||||||
/* register this driver with the USB subsystem */
|
|
||||||
result = usb_register(&piusb_driver);
|
|
||||||
if (result)
|
|
||||||
printk(KERN_ERR KBUILD_MODNAME
|
|
||||||
": usb_register failed. Error number %d\n",
|
|
||||||
result);
|
|
||||||
else
|
|
||||||
printk(KERN_INFO KBUILD_MODNAME ":%s: %s\n", DRIVER_DESC,
|
|
||||||
DRIVER_VERSION);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* piusb_exit
|
|
||||||
*/
|
|
||||||
static void __exit piusb_exit(void)
|
|
||||||
{
|
|
||||||
/* deregister this driver with the USB subsystem */
|
|
||||||
usb_deregister(&piusb_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(piusb_init);
|
|
||||||
module_exit(piusb_exit);
|
|
||||||
|
|
||||||
/* Module parameters */
|
|
||||||
module_param(debug, int, 0);
|
|
||||||
MODULE_PARM_DESC(debug, "Debug enabled or not");
|
|
||||||
|
|
||||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
|
||||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef __RSPIUSB_H
|
|
||||||
#define __RSPIUSB_H
|
|
||||||
|
|
||||||
#define PIUSB_MAGIC 'm'
|
|
||||||
#define PIUSB_IOCTL_BASE 192
|
|
||||||
|
|
||||||
#define PIUSB_IOR(offset) \
|
|
||||||
_IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset, struct ioctl_struct)
|
|
||||||
#define PIUSB_IOW(offset) \
|
|
||||||
_IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset, struct ioctl_struct)
|
|
||||||
#define PIUSB_IO(offset) \
|
|
||||||
_IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset)
|
|
||||||
|
|
||||||
#define PIUSB_GETVNDCMD PIUSB_IOR(1)
|
|
||||||
#define PIUSB_SETVNDCMD PIUSB_IOW(2)
|
|
||||||
#define PIUSB_WRITEPIPE PIUSB_IOW(3)
|
|
||||||
#define PIUSB_READPIPE PIUSB_IOR(4)
|
|
||||||
#define PIUSB_SETFRAMESIZE PIUSB_IOW(5)
|
|
||||||
#define PIUSB_WHATCAMERA PIUSB_IO(6)
|
|
||||||
#define PIUSB_USERBUFFER PIUSB_IOW(7)
|
|
||||||
#define PIUSB_ISHIGHSPEED PIUSB_IO(8)
|
|
||||||
#define PIUSB_UNMAP_USERBUFFER PIUSB_IOW(9)
|
|
||||||
|
|
||||||
struct ioctl_struct {
|
|
||||||
unsigned char cmd;
|
|
||||||
unsigned long numbytes;
|
|
||||||
unsigned char dir; /* 1=out; 0=in */
|
|
||||||
int endpoint;
|
|
||||||
int numFrames;
|
|
||||||
unsigned char *pData;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user