Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
152
drivers/usb/misc/Kconfig
Normal file
152
drivers/usb/misc/Kconfig
Normal file
@@ -0,0 +1,152 @@
|
||||
#
|
||||
# USB Miscellaneous driver configuration
|
||||
#
|
||||
comment "USB Miscellaneous drivers"
|
||||
depends on USB
|
||||
|
||||
config USB_EMI62
|
||||
tristate "EMI 6|2m USB Audio interface support"
|
||||
depends on USB
|
||||
---help---
|
||||
This driver loads firmware to Emagic EMI 6|2m low latency USB
|
||||
Audio and Midi interface.
|
||||
|
||||
After firmware load the device is handled with standard linux
|
||||
USB Audio driver.
|
||||
|
||||
This code is also available as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want).
|
||||
The module will be called audio. If you want to compile it as a
|
||||
module, say M here and read <file:Documentation/kbuild/modules.txt>.
|
||||
|
||||
config USB_EMI26
|
||||
tristate "EMI 2|6 USB Audio interface support"
|
||||
depends on USB
|
||||
---help---
|
||||
This driver loads firmware to Emagic EMI 2|6 low latency USB
|
||||
Audio interface.
|
||||
|
||||
After firmware load the device is handled with standard linux
|
||||
USB Audio driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called emi26.
|
||||
|
||||
config USB_AUERSWALD
|
||||
tristate "USB Auerswald ISDN support (EXPERIMENTAL)"
|
||||
depends on USB && EXPERIMENTAL
|
||||
help
|
||||
Say Y here if you want to connect an Auerswald USB ISDN Device
|
||||
to your computer's USB port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called auerswald.
|
||||
|
||||
config USB_RIO500
|
||||
tristate "USB Diamond Rio500 support (EXPERIMENTAL)"
|
||||
depends on USB && EXPERIMENTAL
|
||||
help
|
||||
Say Y here if you want to connect a USB Rio500 mp3 player to your
|
||||
computer's USB port. Please read <file:Documentation/usb/rio.txt>
|
||||
for more information.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rio500.
|
||||
|
||||
config USB_LEGOTOWER
|
||||
tristate "USB Lego Infrared Tower support (EXPERIMENTAL)"
|
||||
depends on USB && EXPERIMENTAL
|
||||
help
|
||||
Say Y here if you want to connect a USB Lego Infrared Tower to your
|
||||
computer's USB port.
|
||||
|
||||
This code is also available as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want).
|
||||
The module will be called legousbtower. If you want to compile it as
|
||||
a module, say M here and read
|
||||
<file:Documentation/kbuild/modules.txt>.
|
||||
|
||||
config USB_LCD
|
||||
tristate "USB LCD driver support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect an USBLCD to your computer's
|
||||
USB port. The USBLCD is a small USB interface board for
|
||||
alphanumeric LCD modules. See <http://www.usblcd.de/> for more
|
||||
information.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called usblcd.
|
||||
|
||||
config USB_LED
|
||||
tristate "USB LED driver support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect an USBLED device to your
|
||||
computer's USB port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called usbled.
|
||||
|
||||
config USB_CYTHERM
|
||||
tristate "Cypress USB thermometer driver support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect a Cypress USB thermometer
|
||||
device to your computer's USB port. This device is also known
|
||||
as the Cypress USB Starter kit or demo board. The Elektor
|
||||
magazine published a modified version of this device in issue
|
||||
#291.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cytherm.
|
||||
|
||||
config USB_PHIDGETKIT
|
||||
tristate "USB PhidgetKit support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect a PhidgetKit USB device from
|
||||
Phidgets Inc.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called phidgetkit.
|
||||
|
||||
config USB_PHIDGETSERVO
|
||||
tristate "USB PhidgetServo support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
|
||||
servo controller version 2.0 or 3.0.
|
||||
|
||||
Phidgets Inc. has a web page at <http://www.phidgets.com/>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called phidgetservo.
|
||||
|
||||
config USB_IDMOUSE
|
||||
tristate "Siemens ID USB Mouse Fingerprint sensor support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to use the fingerprint sensor on
|
||||
the Siemens ID Mouse. There is also a Siemens ID Mouse
|
||||
_Professional_, which has not been tested with this driver,
|
||||
but uses the same sensor and may therefore work.
|
||||
|
||||
This driver creates an entry "/dev/idmouseX" or "/dev/usb/idmouseX",
|
||||
which can be used by, e.g.,"cat /dev/idmouse0 > fingerprint.pnm".
|
||||
|
||||
See also <http://www.fs.tum.de/~echtler/idmouse/>.
|
||||
|
||||
source "drivers/usb/misc/sisusbvga/Kconfig"
|
||||
|
||||
config USB_TEST
|
||||
tristate "USB testing driver (DEVELOPMENT)"
|
||||
depends on USB && USB_DEVICEFS && EXPERIMENTAL
|
||||
help
|
||||
This driver is for testing host controller software. It is used
|
||||
with specialized device firmware for regression and stress testing,
|
||||
to help prevent problems from cropping up with "real" drivers.
|
||||
|
||||
See <http://www.linux-usb.org/usbtest/> for more information,
|
||||
including sample test device firmware and "how to use it".
|
||||
|
20
drivers/usb/misc/Makefile
Normal file
20
drivers/usb/misc/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Makefile for the rest of the USB drivers
|
||||
# (the ones that don't fit into any other categories)
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
|
||||
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
|
||||
obj-$(CONFIG_USB_EMI26) += emi26.o
|
||||
obj-$(CONFIG_USB_EMI62) += emi62.o
|
||||
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
|
||||
obj-$(CONFIG_USB_LCD) += usblcd.o
|
||||
obj-$(CONFIG_USB_LED) += usbled.o
|
||||
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
|
||||
obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
|
||||
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
|
||||
obj-$(CONFIG_USB_RIO500) += rio500.o
|
||||
obj-$(CONFIG_USB_TEST) += usbtest.o
|
||||
obj-$(CONFIG_USB_USS720) += uss720.o
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
|
2163
drivers/usb/misc/auerswald.c
Normal file
2163
drivers/usb/misc/auerswald.c
Normal file
文件差異過大導致無法顯示
Load Diff
430
drivers/usb/misc/cytherm.c
Normal file
430
drivers/usb/misc/cytherm.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/* -*- linux-c -*-
|
||||
* Cypress USB Thermometer driver
|
||||
*
|
||||
* Copyright (c) 2004 Erik Rigtorp <erkki@linux.nu> <erik@rigtorp.com>
|
||||
*
|
||||
* This driver works with Elektor magazine USB Interface as published in
|
||||
* issue #291. It should also work with the original starter kit/demo board
|
||||
* from Cypress.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define DRIVER_VERSION "v1.0"
|
||||
#define DRIVER_AUTHOR "Erik Rigtorp"
|
||||
#define DRIVER_DESC "Cypress USB Thermometer driver"
|
||||
|
||||
#define USB_SKEL_VENDOR_ID 0x04b4
|
||||
#define USB_SKEL_PRODUCT_ID 0x0002
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
||||
/* Structure to hold all of our device specific stuff */
|
||||
struct usb_cytherm {
|
||||
struct usb_device *udev; /* save off the usb device pointer */
|
||||
struct usb_interface *interface; /* the interface for this device */
|
||||
int brightness;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
static int cytherm_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id);
|
||||
static void cytherm_disconnect(struct usb_interface *interface);
|
||||
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver cytherm_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cytherm",
|
||||
.probe = cytherm_probe,
|
||||
.disconnect = cytherm_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
/* Vendor requests */
|
||||
/* They all operate on one byte at a time */
|
||||
#define PING 0x00
|
||||
#define READ_ROM 0x01 /* Reads form ROM, value = address */
|
||||
#define READ_RAM 0x02 /* Reads form RAM, value = address */
|
||||
#define WRITE_RAM 0x03 /* Write to RAM, value = address, index = data */
|
||||
#define READ_PORT 0x04 /* Reads from port, value = address */
|
||||
#define WRITE_PORT 0x05 /* Write to port, value = address, index = data */
|
||||
|
||||
|
||||
/* Send a vendor command to device */
|
||||
static int vendor_command(struct usb_device *dev, unsigned char request,
|
||||
unsigned char value, unsigned char index,
|
||||
void *buf, int size)
|
||||
{
|
||||
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
request,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
|
||||
value,
|
||||
index, buf, size,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define BRIGHTNESS 0x2c /* RAM location for brightness value */
|
||||
#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */
|
||||
|
||||
static ssize_t show_brightness(struct device *dev, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "%i", cytherm->brightness);
|
||||
}
|
||||
|
||||
static ssize_t set_brightness(struct device *dev, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
unsigned char *buffer;
|
||||
int retval;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cytherm->brightness = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (cytherm->brightness > 0xFF)
|
||||
cytherm->brightness = 0xFF;
|
||||
else if (cytherm->brightness < 0)
|
||||
cytherm->brightness = 0;
|
||||
|
||||
/* Set brightness */
|
||||
retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS,
|
||||
cytherm->brightness, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
/* Inform <20>C that we have changed the brightness setting */
|
||||
retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
|
||||
0x01, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP,
|
||||
show_brightness, set_brightness);
|
||||
|
||||
|
||||
#define TEMP 0x33 /* RAM location for temperature */
|
||||
#define SIGN 0x34 /* RAM location for temperature sign */
|
||||
|
||||
static ssize_t show_temp(struct device *dev, char *buf)
|
||||
{
|
||||
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
int temp, sign;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read temperature */
|
||||
retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
temp = buffer[1];
|
||||
|
||||
/* read sign */
|
||||
retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
sign = buffer[1];
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
|
||||
5*(temp - ((temp >> 1) << 1)));
|
||||
}
|
||||
|
||||
|
||||
static ssize_t set_temp(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
|
||||
|
||||
|
||||
#define BUTTON 0x7a
|
||||
|
||||
static ssize_t show_button(struct device *dev, char *buf)
|
||||
{
|
||||
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check button */
|
||||
retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
retval = buffer[1];
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
if (retval)
|
||||
return sprintf(buf, "1");
|
||||
else
|
||||
return sprintf(buf, "0");
|
||||
}
|
||||
|
||||
|
||||
static ssize_t set_button(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
|
||||
|
||||
|
||||
static ssize_t show_port0(struct device *dev, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
retval = buffer[1];
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return sprintf(buf, "%d", retval);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t set_port0(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
unsigned char *buffer;
|
||||
int retval;
|
||||
int tmp;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (tmp > 0xFF)
|
||||
tmp = 0xFF;
|
||||
else if (tmp < 0)
|
||||
tmp = 0;
|
||||
|
||||
retval = vendor_command(cytherm->udev, WRITE_PORT, 0,
|
||||
tmp, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
|
||||
|
||||
static ssize_t show_port1(struct device *dev, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
retval = buffer[1];
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return sprintf(buf, "%d", retval);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t set_port1(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_cytherm *cytherm = usb_get_intfdata(intf);
|
||||
|
||||
unsigned char *buffer;
|
||||
int retval;
|
||||
int tmp;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&cytherm->udev->dev, "out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (tmp > 0xFF)
|
||||
tmp = 0xFF;
|
||||
else if (tmp < 0)
|
||||
tmp = 0;
|
||||
|
||||
retval = vendor_command(cytherm->udev, WRITE_PORT, 1,
|
||||
tmp, buffer, 8);
|
||||
if (retval)
|
||||
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
|
||||
|
||||
|
||||
|
||||
static int cytherm_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_cytherm *dev = NULL;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev_err (&interface->dev, "Out of memory\n");
|
||||
goto error;
|
||||
}
|
||||
memset (dev, 0x00, sizeof (*dev));
|
||||
|
||||
dev->udev = usb_get_dev(udev);
|
||||
|
||||
usb_set_intfdata (interface, dev);
|
||||
|
||||
dev->brightness = 0xFF;
|
||||
|
||||
device_create_file(&interface->dev, &dev_attr_brightness);
|
||||
device_create_file(&interface->dev, &dev_attr_temp);
|
||||
device_create_file(&interface->dev, &dev_attr_button);
|
||||
device_create_file(&interface->dev, &dev_attr_port0);
|
||||
device_create_file(&interface->dev, &dev_attr_port1);
|
||||
|
||||
dev_info (&interface->dev,
|
||||
"Cypress thermometer device now attached\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void cytherm_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_cytherm *dev;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
usb_set_intfdata (interface, NULL);
|
||||
|
||||
device_remove_file(&interface->dev, &dev_attr_brightness);
|
||||
device_remove_file(&interface->dev, &dev_attr_temp);
|
||||
device_remove_file(&interface->dev, &dev_attr_button);
|
||||
device_remove_file(&interface->dev, &dev_attr_port0);
|
||||
device_remove_file(&interface->dev, &dev_attr_port1);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
kfree(dev);
|
||||
|
||||
dev_info(&interface->dev, "Cypress thermometer now disconnected\n");
|
||||
}
|
||||
|
||||
|
||||
static int __init usb_cytherm_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = usb_register(&cytherm_driver);
|
||||
if (result)
|
||||
{
|
||||
err("usb_register failed. Error number %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
info(DRIVER_VERSION ":" DRIVER_DESC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit usb_cytherm_exit(void)
|
||||
{
|
||||
usb_deregister(&cytherm_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init (usb_cytherm_init);
|
||||
module_exit (usb_cytherm_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
255
drivers/usb/misc/emi26.c
Normal file
255
drivers/usb/misc/emi26.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Emagic EMI 2|6 usb audio interface firmware loader.
|
||||
* Copyright (C) 2002
|
||||
* Tapio Laxstr<74>m (tapio.laxstrom@iptime.fi)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* emi26.c,v 1.13 2002/03/08 13:10:26 tapio Exp
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define MAX_INTEL_HEX_RECORD_LENGTH 16
|
||||
typedef struct _INTEL_HEX_RECORD
|
||||
{
|
||||
__u32 length;
|
||||
__u32 address;
|
||||
__u32 type;
|
||||
__u8 data[MAX_INTEL_HEX_RECORD_LENGTH];
|
||||
} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
|
||||
|
||||
/* include firmware (variables) */
|
||||
#include "emi26_fw.h"
|
||||
|
||||
#define EMI26_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */
|
||||
#define EMI26_PRODUCT_ID 0x0100 /* EMI 2|6 without firmware */
|
||||
#define EMI26B_PRODUCT_ID 0x0102 /* EMI 2|6 without firmware */
|
||||
|
||||
#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */
|
||||
#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */
|
||||
#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */
|
||||
#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */
|
||||
#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
|
||||
#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS)
|
||||
|
||||
static int emi26_writememory( struct usb_device *dev, int address, unsigned char *data, int length, __u8 bRequest);
|
||||
static int emi26_set_reset(struct usb_device *dev, unsigned char reset_bit);
|
||||
static int emi26_load_firmware (struct usb_device *dev);
|
||||
static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *id);
|
||||
static void emi26_disconnect(struct usb_interface *intf);
|
||||
static int __init emi26_init (void);
|
||||
static void __exit emi26_exit (void);
|
||||
|
||||
|
||||
/* thanks to drivers/usb/serial/keyspan_pda.c code */
|
||||
static int emi26_writememory (struct usb_device *dev, int address, unsigned char *data, int length, __u8 request)
|
||||
{
|
||||
int result;
|
||||
unsigned char *buffer = kmalloc (length, GFP_KERNEL);
|
||||
|
||||
if (!buffer) {
|
||||
err("emi26: kmalloc(%d) failed.", length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy (buffer, data, length);
|
||||
/* Note: usb_control_msg returns negative value on error or length of the
|
||||
* data that was written! */
|
||||
result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300);
|
||||
kfree (buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* thanks to drivers/usb/serial/keyspan_pda.c code */
|
||||
static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit)
|
||||
{
|
||||
int response;
|
||||
info("%s - %d", __FUNCTION__, reset_bit);
|
||||
/* printk(KERN_DEBUG "%s - %d", __FUNCTION__, reset_bit); */
|
||||
response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
|
||||
if (response < 0) {
|
||||
err("emi26: set_reset (%d) failed", reset_bit);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
#define FW_LOAD_SIZE 1023
|
||||
|
||||
static int emi26_load_firmware (struct usb_device *dev)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
int pos = 0; /* Position in hex record */
|
||||
__u32 addr; /* Address to write */
|
||||
__u8 *buf;
|
||||
|
||||
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM);
|
||||
err = -ENOMEM;
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi26_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err( "%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 1. We need to put the loader for the FPGA into the EZ-USB */
|
||||
for (i=0; g_Loader[i].type == 0; i++) {
|
||||
err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi26_set_reset(dev,0);
|
||||
|
||||
/* 2. We upload the FPGA firmware into the EMI
|
||||
* Note: collect up to 1023 (yes!) bytes and send them with
|
||||
* a single request. This is _much_ faster! */
|
||||
do {
|
||||
i = 0;
|
||||
addr = g_bitstream[pos].address;
|
||||
|
||||
/* intel hex records are terminated with type 0 element */
|
||||
while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < FW_LOAD_SIZE)) {
|
||||
memcpy(buf + i, g_bitstream[pos].data, g_bitstream[pos].length);
|
||||
i += g_bitstream[pos].length;
|
||||
pos++;
|
||||
}
|
||||
err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
} while (i > 0);
|
||||
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi26_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
|
||||
for (i=0; g_Loader[i].type == 0; i++) {
|
||||
err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi26_set_reset(dev,0);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
|
||||
for (i=0; g_Firmware[i].type == 0; i++) {
|
||||
if (!INTERNAL_RAM(g_Firmware[i].address)) {
|
||||
err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi26_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
for (i=0; g_Firmware[i].type == 0; i++) {
|
||||
if (INTERNAL_RAM(g_Firmware[i].address)) {
|
||||
err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi26_set_reset(dev,0);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* return 1 to fail the driver inialization
|
||||
* and give real driver change to load */
|
||||
err = 1;
|
||||
|
||||
wraperr:
|
||||
kfree(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) },
|
||||
{ USB_DEVICE(EMI26_VENDOR_ID, EMI26B_PRODUCT_ID) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
||||
static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
|
||||
info("%s start", __FUNCTION__);
|
||||
|
||||
emi26_load_firmware(dev);
|
||||
|
||||
/* do not return the driver context, let real audio driver do that */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void emi26_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
}
|
||||
|
||||
static struct usb_driver emi26_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "emi26 - firmware loader",
|
||||
.probe = emi26_probe,
|
||||
.disconnect = emi26_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
static int __init emi26_init (void)
|
||||
{
|
||||
return usb_register(&emi26_driver);
|
||||
}
|
||||
|
||||
static void __exit emi26_exit (void)
|
||||
{
|
||||
usb_deregister (&emi26_driver);
|
||||
}
|
||||
|
||||
module_init(emi26_init);
|
||||
module_exit(emi26_exit);
|
||||
|
||||
MODULE_AUTHOR("tapio laxstr<74>m");
|
||||
MODULE_DESCRIPTION("Emagic EMI 2|6 firmware loader.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* vi:ai:syntax=c:sw=8:ts=8:tw=80
|
||||
*/
|
5779
drivers/usb/misc/emi26_fw.h
Normal file
5779
drivers/usb/misc/emi26_fw.h
Normal file
文件差異過大導致無法顯示
Load Diff
298
drivers/usb/misc/emi62.c
Normal file
298
drivers/usb/misc/emi62.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Emagic EMI 2|6 usb audio interface firmware loader.
|
||||
* Copyright (C) 2002
|
||||
* Tapio Laxstr<74>m (tapio.laxstrom@iptime.fi)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id: emi62.c,v 1.15 2002/04/23 06:13:59 tapio Exp $
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define MAX_INTEL_HEX_RECORD_LENGTH 16
|
||||
typedef struct _INTEL_HEX_RECORD
|
||||
{
|
||||
__u32 length;
|
||||
__u32 address;
|
||||
__u32 type;
|
||||
__u8 data[MAX_INTEL_HEX_RECORD_LENGTH];
|
||||
} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
|
||||
|
||||
/* include firmware (variables)*/
|
||||
|
||||
/* FIXME: This is quick and dirty solution! */
|
||||
#define SPDIF /* if you want SPDIF comment next line */
|
||||
//#undef SPDIF /* if you want MIDI uncomment this line */
|
||||
|
||||
#ifdef SPDIF
|
||||
# include "emi62_fw_s.h" /* spdif fw */
|
||||
#else
|
||||
# include "emi62_fw_m.h" /* midi fw */
|
||||
#endif
|
||||
|
||||
#define EMI62_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */
|
||||
#define EMI62_PRODUCT_ID 0x0110 /* EMI 6|2m without firmware */
|
||||
|
||||
#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */
|
||||
#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */
|
||||
#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */
|
||||
#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */
|
||||
#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
|
||||
#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS)
|
||||
|
||||
static int emi62_writememory( struct usb_device *dev, int address, unsigned char *data, int length, __u8 bRequest);
|
||||
static int emi62_set_reset(struct usb_device *dev, unsigned char reset_bit);
|
||||
static int emi62_load_firmware (struct usb_device *dev);
|
||||
static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id);
|
||||
static void emi62_disconnect(struct usb_interface *intf);
|
||||
static int __init emi62_init (void);
|
||||
static void __exit emi62_exit (void);
|
||||
|
||||
|
||||
/* thanks to drivers/usb/serial/keyspan_pda.c code */
|
||||
static int emi62_writememory (struct usb_device *dev, int address, unsigned char *data, int length, __u8 request)
|
||||
{
|
||||
int result;
|
||||
unsigned char *buffer = kmalloc (length, GFP_KERNEL);
|
||||
|
||||
if (!buffer) {
|
||||
err("emi62: kmalloc(%d) failed.", length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy (buffer, data, length);
|
||||
/* Note: usb_control_msg returns negative value on error or length of the
|
||||
* data that was written! */
|
||||
result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300);
|
||||
kfree (buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* thanks to drivers/usb/serial/keyspan_pda.c code */
|
||||
static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit)
|
||||
{
|
||||
int response;
|
||||
info("%s - %d", __FUNCTION__, reset_bit);
|
||||
|
||||
response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
|
||||
if (response < 0) {
|
||||
err("emi62: set_reset (%d) failed", reset_bit);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
#define FW_LOAD_SIZE 1023
|
||||
|
||||
static int emi62_load_firmware (struct usb_device *dev)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
int pos = 0; /* Position in hex record */
|
||||
__u32 addr; /* Address to write */
|
||||
__u8 *buf;
|
||||
|
||||
dev_dbg(&dev->dev, "load_firmware\n");
|
||||
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM);
|
||||
err = -ENOMEM;
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi62_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 1. We need to put the loader for the FPGA into the EZ-USB */
|
||||
for (i=0; g_emi62_loader[i].type == 0; i++) {
|
||||
err = emi62_writememory(dev, g_emi62_loader[i].address, g_emi62_loader[i].data, g_emi62_loader[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi62_set_reset(dev,0);
|
||||
|
||||
/* 2. We upload the FPGA firmware into the EMI
|
||||
* Note: collect up to 1023 (yes!) bytes and send them with
|
||||
* a single request. This is _much_ faster! */
|
||||
do {
|
||||
i = 0;
|
||||
addr = g_emi62bs[pos].address;
|
||||
|
||||
/* intel hex records are terminated with type 0 element */
|
||||
while ((g_emi62bs[pos].type == 0) && (i + g_emi62bs[pos].length < FW_LOAD_SIZE)) {
|
||||
memcpy(buf + i, g_emi62bs[pos].data, g_emi62bs[pos].length);
|
||||
i += g_emi62bs[pos].length;
|
||||
pos++;
|
||||
}
|
||||
err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
} while (i > 0);
|
||||
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi62_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
|
||||
for (i=0; g_emi62_loader[i].type == 0; i++) {
|
||||
err = emi62_writememory(dev, g_emi62_loader[i].address, g_emi62_loader[i].data, g_emi62_loader[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi62_set_reset(dev,0);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
|
||||
|
||||
/* FIXME: quick and dirty ifdefs */
|
||||
#ifdef SPDIF
|
||||
for (i=0; g_HexSpdifFw62[i].type == 0; i++) {
|
||||
if (!INTERNAL_RAM(g_HexSpdifFw62[i].address)) {
|
||||
err = emi62_writememory(dev, g_HexSpdifFw62[i].address, g_HexSpdifFw62[i].data, g_HexSpdifFw62[i].length, ANCHOR_LOAD_EXTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else /* MIDI */
|
||||
for (i=0; g_HexMidiFw62[i].type == 0; i++) {
|
||||
if (!INTERNAL_RAM(g_HexMidiFw62[i].address)) {
|
||||
err = emi62_writememory(dev, g_HexMidiFw62[i].address, g_HexMidiFw62[i].data, g_HexMidiFw62[i].length, ANCHOR_LOAD_EXTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d\n", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Assert reset (stop the CPU in the EMI) */
|
||||
err = emi62_set_reset(dev,1);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
/* FIXME: quick and dirty ifdefs */
|
||||
#ifdef SPDIF
|
||||
for (i=0; g_HexSpdifFw62[i].type == 0; i++) {
|
||||
if (INTERNAL_RAM(g_HexSpdifFw62[i].address)) {
|
||||
err = emi62_writememory(dev, g_HexSpdifFw62[i].address, g_HexSpdifFw62[i].data, g_HexSpdifFw62[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else /* MIDI */
|
||||
for (i=0; g_HexMidiFw62[i].type == 0; i++) {
|
||||
if (INTERNAL_RAM(g_HexMidiFw62[i].address)) {
|
||||
err = emi62_writememory(dev, g_HexMidiFw62[i].address, g_HexMidiFw62[i].data, g_HexMidiFw62[i].length, ANCHOR_LOAD_INTERNAL);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d\n", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* De-assert reset (let the CPU run) */
|
||||
err = emi62_set_reset(dev,0);
|
||||
if (err < 0) {
|
||||
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
|
||||
goto wraperr;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
/* return 1 to fail the driver inialization
|
||||
* and give real driver change to load */
|
||||
return 1;
|
||||
|
||||
wraperr:
|
||||
kfree(buf);
|
||||
dev_err(&dev->dev, "Error\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
static __devinitdata struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
||||
static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
dev_dbg(&intf->dev, "emi62_probe\n");
|
||||
|
||||
info("%s start", __FUNCTION__);
|
||||
|
||||
emi62_load_firmware(dev);
|
||||
|
||||
/* do not return the driver context, let real audio driver do that */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void emi62_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
}
|
||||
|
||||
static struct usb_driver emi62_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "emi62 - firmware loader",
|
||||
.probe = emi62_probe,
|
||||
.disconnect = emi62_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
static int __init emi62_init (void)
|
||||
{
|
||||
int retval;
|
||||
retval = usb_register (&emi62_driver);
|
||||
if (retval)
|
||||
printk(KERN_ERR "adi-emi: registration failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit emi62_exit (void)
|
||||
{
|
||||
usb_deregister (&emi62_driver);
|
||||
}
|
||||
|
||||
module_init(emi62_init);
|
||||
module_exit(emi62_exit);
|
||||
|
||||
MODULE_AUTHOR("tapio laxstr<74>m");
|
||||
MODULE_DESCRIPTION("Emagic EMI 6|2m firmware loader.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* vi:ai:syntax=c:sw=8:ts=8:tw=80
|
||||
*/
|
8853
drivers/usb/misc/emi62_fw_m.h
Normal file
8853
drivers/usb/misc/emi62_fw_m.h
Normal file
文件差異過大導致無法顯示
Load Diff
8837
drivers/usb/misc/emi62_fw_s.h
Normal file
8837
drivers/usb/misc/emi62_fw_s.h
Normal file
文件差異過大導致無法顯示
Load Diff
443
drivers/usb/misc/idmouse.c
Normal file
443
drivers/usb/misc/idmouse.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/* Siemens ID Mouse driver v0.5
|
||||
|
||||
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.
|
||||
|
||||
Copyright (C) 2004-5 by Florian 'Floe' Echtler <echtler@fs.tum.de>
|
||||
and Andreas 'ad' Deresch <aderesch@fs.tum.de>
|
||||
|
||||
Derived from the USB Skeleton driver 1.1,
|
||||
Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define WIDTH 225
|
||||
#define HEIGHT 288
|
||||
#define HEADER "P5 225 288 255 "
|
||||
#define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
|
||||
|
||||
/* Version Information */
|
||||
#define DRIVER_VERSION "0.5"
|
||||
#define DRIVER_SHORT "idmouse"
|
||||
#define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>"
|
||||
#define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver"
|
||||
|
||||
/* Siemens ID Mouse */
|
||||
#define USB_IDMOUSE_VENDOR_ID 0x0681
|
||||
#define USB_IDMOUSE_PRODUCT_ID 0x0005
|
||||
|
||||
/* we still need a minor number */
|
||||
#define USB_IDMOUSE_MINOR_BASE 132
|
||||
|
||||
static struct usb_device_id idmouse_table[] = {
|
||||
{USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)},
|
||||
{} /* null entry at the end */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, idmouse_table);
|
||||
|
||||
/* structure to hold all of our device specific stuff */
|
||||
struct usb_idmouse {
|
||||
|
||||
struct usb_device *udev; /* save off the usb device pointer */
|
||||
struct usb_interface *interface; /* the interface for this device */
|
||||
|
||||
unsigned char *bulk_in_buffer; /* the buffer to receive data */
|
||||
size_t bulk_in_size; /* the size of the receive buffer */
|
||||
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
|
||||
|
||||
int open; /* if the port is open or not */
|
||||
int present; /* if the device is not disconnected */
|
||||
struct semaphore sem; /* locks this structure */
|
||||
|
||||
};
|
||||
|
||||
/* local function prototypes */
|
||||
static ssize_t idmouse_read(struct file *file, char __user *buffer,
|
||||
size_t count, loff_t * ppos);
|
||||
|
||||
static int idmouse_open(struct inode *inode, struct file *file);
|
||||
static int idmouse_release(struct inode *inode, struct file *file);
|
||||
|
||||
static int idmouse_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id);
|
||||
|
||||
static void idmouse_disconnect(struct usb_interface *interface);
|
||||
|
||||
/* file operation pointers */
|
||||
static struct file_operations idmouse_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = idmouse_read,
|
||||
.open = idmouse_open,
|
||||
.release = idmouse_release,
|
||||
};
|
||||
|
||||
/* class driver information for devfs */
|
||||
static struct usb_class_driver idmouse_class = {
|
||||
.name = "usb/idmouse%d",
|
||||
.fops = &idmouse_fops,
|
||||
.mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */
|
||||
.minor_base = USB_IDMOUSE_MINOR_BASE,
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver idmouse_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_SHORT,
|
||||
.probe = idmouse_probe,
|
||||
.disconnect = idmouse_disconnect,
|
||||
.id_table = idmouse_table,
|
||||
};
|
||||
|
||||
// prevent races between open() and disconnect()
|
||||
static DECLARE_MUTEX(disconnect_sem);
|
||||
|
||||
static int idmouse_create_image(struct usb_idmouse *dev)
|
||||
{
|
||||
int bytes_read = 0;
|
||||
int bulk_read = 0;
|
||||
int result = 0;
|
||||
|
||||
if (dev->bulk_in_size < sizeof(HEADER))
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1);
|
||||
bytes_read += sizeof(HEADER)-1;
|
||||
|
||||
/* Dump the setup packets. Yes, they are uncommented, simply
|
||||
because they were sniffed under Windows using SnoopyPro.
|
||||
I _guess_ that 0x22 is a kind of reset command and 0x21
|
||||
means init..
|
||||
*/
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* loop over a blocking bulk read to get data from the device */
|
||||
while (bytes_read < IMGSIZE) {
|
||||
result = usb_bulk_msg (dev->udev,
|
||||
usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
|
||||
dev->bulk_in_buffer + bytes_read,
|
||||
dev->bulk_in_size, &bulk_read, 5000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
bytes_read += bulk_read;
|
||||
}
|
||||
|
||||
/* reset the device */
|
||||
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
|
||||
0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* should be IMGSIZE == 64815 */
|
||||
dbg("read %d bytes fingerprint data", bytes_read);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void idmouse_delete(struct usb_idmouse *dev)
|
||||
{
|
||||
kfree(dev->bulk_in_buffer);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static int idmouse_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_idmouse *dev = NULL;
|
||||
struct usb_interface *interface;
|
||||
int result = 0;
|
||||
|
||||
/* prevent disconnects */
|
||||
down(&disconnect_sem);
|
||||
|
||||
/* get the interface from minor number and driver information */
|
||||
interface = usb_find_interface (&idmouse_driver, iminor (inode));
|
||||
if (!interface) {
|
||||
up(&disconnect_sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* get the device information block from the interface */
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
up(&disconnect_sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lock this device */
|
||||
down(&dev->sem);
|
||||
|
||||
/* check if already open */
|
||||
if (dev->open) {
|
||||
|
||||
/* already open, so fail */
|
||||
result = -EBUSY;
|
||||
|
||||
} else {
|
||||
|
||||
/* create a new image and check for success */
|
||||
result = idmouse_create_image (dev);
|
||||
if (result)
|
||||
goto error;
|
||||
|
||||
/* increment our usage count for the driver */
|
||||
++dev->open;
|
||||
|
||||
/* save our object in the file's private structure */
|
||||
file->private_data = dev;
|
||||
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
/* unlock this device */
|
||||
up(&dev->sem);
|
||||
|
||||
/* unlock the disconnect semaphore */
|
||||
up(&disconnect_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int idmouse_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
|
||||
/* prevent a race condition with open() */
|
||||
down(&disconnect_sem);
|
||||
|
||||
dev = (struct usb_idmouse *) file->private_data;
|
||||
|
||||
if (dev == NULL) {
|
||||
up(&disconnect_sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lock our device */
|
||||
down(&dev->sem);
|
||||
|
||||
/* are we really open? */
|
||||
if (dev->open <= 0) {
|
||||
up(&dev->sem);
|
||||
up(&disconnect_sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
--dev->open;
|
||||
|
||||
if (!dev->present) {
|
||||
/* the device was unplugged before the file was released */
|
||||
up(&dev->sem);
|
||||
idmouse_delete(dev);
|
||||
up(&disconnect_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
up(&dev->sem);
|
||||
up(&disconnect_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
int result = 0;
|
||||
|
||||
dev = (struct usb_idmouse *) file->private_data;
|
||||
|
||||
// lock this object
|
||||
down (&dev->sem);
|
||||
|
||||
// verify that the device wasn't unplugged
|
||||
if (!dev->present) {
|
||||
up (&dev->sem);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (*ppos >= IMGSIZE) {
|
||||
up (&dev->sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count > IMGSIZE - *ppos)
|
||||
count = IMGSIZE - *ppos;
|
||||
|
||||
if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) {
|
||||
result = -EFAULT;
|
||||
} else {
|
||||
result = count;
|
||||
*ppos += count;
|
||||
}
|
||||
|
||||
// unlock the device
|
||||
up(&dev->sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int idmouse_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_idmouse *dev = NULL;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
size_t buffer_size;
|
||||
int result;
|
||||
|
||||
/* check if we have gotten the data or the hid interface */
|
||||
iface_desc = &interface->altsetting[0];
|
||||
if (iface_desc->desc.bInterfaceClass != 0x0A)
|
||||
return -ENODEV;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (dev == NULL)
|
||||
return -ENOMEM;
|
||||
memset(dev, 0x00, sizeof(*dev));
|
||||
|
||||
init_MUTEX(&dev->sem);
|
||||
dev->udev = udev;
|
||||
dev->interface = interface;
|
||||
|
||||
/* set up the endpoint information - use only the first bulk-in endpoint */
|
||||
endpoint = &iface_desc->endpoint[0].desc;
|
||||
if (!dev->bulk_in_endpointAddr
|
||||
&& (endpoint->bEndpointAddress & USB_DIR_IN)
|
||||
&& ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
USB_ENDPOINT_XFER_BULK)) {
|
||||
|
||||
/* we found a bulk in endpoint */
|
||||
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
dev->bulk_in_size = buffer_size;
|
||||
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
dev->bulk_in_buffer =
|
||||
kmalloc(IMGSIZE + buffer_size, GFP_KERNEL);
|
||||
|
||||
if (!dev->bulk_in_buffer) {
|
||||
err("Unable to allocate input buffer.");
|
||||
idmouse_delete(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dev->bulk_in_endpointAddr)) {
|
||||
err("Unable to find bulk-in endpoint.");
|
||||
idmouse_delete(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* allow device read, write and ioctl */
|
||||
dev->present = 1;
|
||||
|
||||
/* we can register the device now, as it is ready */
|
||||
usb_set_intfdata(interface, dev);
|
||||
result = usb_register_dev(interface, &idmouse_class);
|
||||
if (result) {
|
||||
/* something prevented us from registering this device */
|
||||
err("Unble to allocate minor number.");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
idmouse_delete(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* be noisy */
|
||||
dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idmouse_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
|
||||
/* prevent races with open() */
|
||||
down(&disconnect_sem);
|
||||
|
||||
/* get device structure */
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* lock it */
|
||||
down(&dev->sem);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &idmouse_class);
|
||||
|
||||
/* prevent device read, write and ioctl */
|
||||
dev->present = 0;
|
||||
|
||||
/* unlock */
|
||||
up(&dev->sem);
|
||||
|
||||
/* if the device is opened, idmouse_release will clean this up */
|
||||
if (!dev->open)
|
||||
idmouse_delete(dev);
|
||||
|
||||
up(&disconnect_sem);
|
||||
|
||||
info("%s disconnected", DRIVER_DESC);
|
||||
}
|
||||
|
||||
static int __init usb_idmouse_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
info(DRIVER_DESC " " DRIVER_VERSION);
|
||||
|
||||
/* register this driver with the USB subsystem */
|
||||
result = usb_register(&idmouse_driver);
|
||||
if (result)
|
||||
err("Unable to register device (error %d).", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit usb_idmouse_exit(void)
|
||||
{
|
||||
/* deregister this driver with the USB subsystem */
|
||||
usb_deregister(&idmouse_driver);
|
||||
}
|
||||
|
||||
module_init(usb_idmouse_init);
|
||||
module_exit(usb_idmouse_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
1088
drivers/usb/misc/legousbtower.c
Normal file
1088
drivers/usb/misc/legousbtower.c
Normal file
文件差異過大導致無法顯示
Load Diff
586
drivers/usb/misc/phidgetkit.c
Normal file
586
drivers/usb/misc/phidgetkit.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* USB PhidgetInterfaceKit driver 1.0
|
||||
*
|
||||
* Copyright (C) 2004 Sean Young <sean@mess.org>
|
||||
* Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
|
||||
*
|
||||
* 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 is a driver for the USB PhidgetInterfaceKit.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
|
||||
#define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
|
||||
|
||||
#define USB_VENDOR_ID_GLAB 0x06c2
|
||||
#define USB_DEVICE_ID_INTERFACEKIT004 0x0040
|
||||
#define USB_DEVICE_ID_INTERFACEKIT888 0x0045
|
||||
#define USB_DEVICE_ID_INTERFACEKIT047 0x0051
|
||||
#define USB_DEVICE_ID_INTERFACEKIT088 0x0053
|
||||
|
||||
#define USB_VENDOR_ID_WISEGROUP 0x0925
|
||||
#define USB_DEVICE_ID_INTERFACEKIT884 0x8201
|
||||
|
||||
#define MAX_INTERFACES 8
|
||||
|
||||
struct driver_interfacekit {
|
||||
int sensors;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int has_lcd;
|
||||
};
|
||||
#define ifkit(_sensors, _inputs, _outputs, _lcd) \
|
||||
static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \
|
||||
.sensors = _sensors, \
|
||||
.inputs = _inputs, \
|
||||
.outputs = _outputs, \
|
||||
.has_lcd = _lcd, \
|
||||
};
|
||||
ifkit(0, 0, 4, 0);
|
||||
ifkit(8, 8, 8, 0);
|
||||
ifkit(0, 4, 7, 1);
|
||||
ifkit(8, 8, 4, 0);
|
||||
ifkit(0, 8, 8, 1);
|
||||
|
||||
struct phidget_interfacekit {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct driver_interfacekit *ifkit;
|
||||
int outputs[MAX_INTERFACES];
|
||||
int inputs[MAX_INTERFACES];
|
||||
int sensors[MAX_INTERFACES];
|
||||
u8 lcd_files_on;
|
||||
|
||||
struct urb *irq;
|
||||
unsigned char *data;
|
||||
dma_addr_t data_dma;
|
||||
};
|
||||
|
||||
static struct usb_device_id id_table[] = {
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
|
||||
.driver_info = (kernel_ulong_t)&ph_004},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888),
|
||||
.driver_info = (kernel_ulong_t)&ph_888},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
|
||||
.driver_info = (kernel_ulong_t)&ph_047},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
|
||||
.driver_info = (kernel_ulong_t)&ph_088},
|
||||
{USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884),
|
||||
.driver_info = (kernel_ulong_t)&ph_884},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static int change_outputs(struct phidget_interfacekit *kit, int output_num, int enable)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
int retval;
|
||||
int n;
|
||||
|
||||
buffer = kmalloc(4, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n",
|
||||
__FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kit->outputs[output_num] = enable;
|
||||
memset(buffer, 0, 4);
|
||||
for (n=0; n<8; n++) {
|
||||
if (kit->outputs[n]) {
|
||||
buffer[0] |= 1 << n;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]);
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2000);
|
||||
|
||||
if (retval != 4)
|
||||
dev_err(&kit->udev->dev, "usb_control_msg returned %d\n",
|
||||
retval);
|
||||
kfree(buffer);
|
||||
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static int change_string(struct phidget_interfacekit *kit, const char *display, unsigned char row)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
unsigned char *form_buffer;
|
||||
int retval = -ENOMEM;
|
||||
int i,j, len, buf_ptr;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
form_buffer = kmalloc(30, GFP_KERNEL);
|
||||
if ((!buffer) || (!form_buffer)) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = strlen(display);
|
||||
if (len > 20)
|
||||
len = 20;
|
||||
|
||||
dev_dbg(&kit->udev->dev, "Setting LCD line %d to %s\n", row, display);
|
||||
|
||||
form_buffer[0] = row * 0x40 + 0x80;
|
||||
form_buffer[1] = 0x02;
|
||||
buf_ptr = 2;
|
||||
for (i = 0; i<len; i++)
|
||||
form_buffer[buf_ptr++] = display[i];
|
||||
|
||||
for (i = 0; i < (20 - len); i++)
|
||||
form_buffer[buf_ptr++] = 0x20;
|
||||
form_buffer[buf_ptr++] = 0x01;
|
||||
form_buffer[buf_ptr++] = row * 0x40 + 0x80 + strlen(display);
|
||||
|
||||
for (i = 0; i < buf_ptr; i += 7) {
|
||||
if ((buf_ptr - i) > 7)
|
||||
len = 7;
|
||||
else
|
||||
len = (buf_ptr - i);
|
||||
for (j = 0; j < len; j++)
|
||||
buffer[j] = form_buffer[i + j];
|
||||
buffer[7] = len;
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
exit:
|
||||
kfree(buffer);
|
||||
kfree(form_buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define set_lcd_line(number) \
|
||||
static ssize_t lcd_line_##number(struct device *dev, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
|
||||
change_string(kit, buf, number - 1); \
|
||||
return count; \
|
||||
} \
|
||||
static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number);
|
||||
set_lcd_line(1);
|
||||
set_lcd_line(2);
|
||||
|
||||
static ssize_t set_backlight(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf);
|
||||
int enabled;
|
||||
unsigned char *buffer;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%d", &enabled) < 1) {
|
||||
retval = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
memset(buffer, 0x00, 8);
|
||||
if (enabled)
|
||||
buffer[0] = 0x01;
|
||||
buffer[7] = 0x11;
|
||||
|
||||
dev_dbg(&kit->udev->dev, "Setting backlight to %s\n", enabled ? "on" : "off");
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
retval = count;
|
||||
exit:
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
|
||||
|
||||
static void remove_lcd_files(struct phidget_interfacekit *kit)
|
||||
{
|
||||
if (kit->lcd_files_on) {
|
||||
dev_dbg(&kit->udev->dev, "Removing lcd files\n");
|
||||
device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1);
|
||||
device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2);
|
||||
device_remove_file(&kit->intf->dev, &dev_attr_backlight);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t enable_lcd_files(struct device *dev, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf);
|
||||
int enable;
|
||||
|
||||
if (kit->ifkit->has_lcd == 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (sscanf(buf, "%d", &enable) < 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable) {
|
||||
if (!kit->lcd_files_on) {
|
||||
dev_dbg(&kit->udev->dev, "Adding lcd files\n");
|
||||
device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1);
|
||||
device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2);
|
||||
device_create_file(&kit->intf->dev, &dev_attr_backlight);
|
||||
kit->lcd_files_on = 1;
|
||||
}
|
||||
} else {
|
||||
if (kit->lcd_files_on) {
|
||||
remove_lcd_files(kit);
|
||||
kit->lcd_files_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
|
||||
|
||||
static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct phidget_interfacekit *kit = urb->context;
|
||||
unsigned char *buffer = kit->data;
|
||||
int status;
|
||||
int n;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0: /* success */
|
||||
break;
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
/* -EPIPE: should clear the halt */
|
||||
default: /* error */
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
for (n=0; n<8; n++) {
|
||||
kit->inputs[n] = buffer[1] & (1 << n) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (buffer[0] & 1) {
|
||||
kit->sensors[4] = buffer[2] + (buffer[3] & 0x0f) * 256;
|
||||
kit->sensors[5] = buffer[4] + (buffer[3] & 0xf0) * 16;
|
||||
kit->sensors[6] = buffer[5] + (buffer[6] & 0x0f) * 256;
|
||||
kit->sensors[7] = buffer[7] + (buffer[6] & 0xf0) * 16;
|
||||
} else {
|
||||
kit->sensors[0] = buffer[2] + (buffer[3] & 0x0f) * 256;
|
||||
kit->sensors[1] = buffer[4] + (buffer[3] & 0xf0) * 16;
|
||||
kit->sensors[2] = buffer[5] + (buffer[6] & 0x0f) * 256;
|
||||
kit->sensors[3] = buffer[7] + (buffer[6] & 0xf0) * 16;
|
||||
}
|
||||
|
||||
resubmit:
|
||||
status = usb_submit_urb(urb, SLAB_ATOMIC);
|
||||
if (status)
|
||||
err("can't resubmit intr, %s-%s/interfacekit0, status %d",
|
||||
kit->udev->bus->bus_name,
|
||||
kit->udev->devpath, status);
|
||||
}
|
||||
|
||||
#define show_set_output(value) \
|
||||
static ssize_t set_output##value(struct device *dev, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
|
||||
int enabled; \
|
||||
int retval; \
|
||||
\
|
||||
if (sscanf(buf, "%d", &enabled) < 1) { \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
retval = change_outputs(kit, value - 1, enabled ? 1 : 0); \
|
||||
\
|
||||
return retval ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_output##value(struct device *dev, char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", kit->outputs[value - 1]); \
|
||||
} \
|
||||
static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \
|
||||
show_output##value, set_output##value);
|
||||
show_set_output(1);
|
||||
show_set_output(2);
|
||||
show_set_output(3);
|
||||
show_set_output(4);
|
||||
show_set_output(5);
|
||||
show_set_output(6);
|
||||
show_set_output(7);
|
||||
show_set_output(8); /* should be MAX_INTERFACES - 1 */
|
||||
|
||||
#define show_input(value) \
|
||||
static ssize_t show_input##value(struct device *dev, char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", kit->inputs[value - 1]); \
|
||||
} \
|
||||
static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
|
||||
|
||||
show_input(1);
|
||||
show_input(2);
|
||||
show_input(3);
|
||||
show_input(4);
|
||||
show_input(5);
|
||||
show_input(6);
|
||||
show_input(7);
|
||||
show_input(8); /* should be MAX_INTERFACES - 1 */
|
||||
|
||||
#define show_sensor(value) \
|
||||
static ssize_t show_sensor##value(struct device *dev, char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", kit->sensors[value - 1]); \
|
||||
} \
|
||||
static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
|
||||
|
||||
show_sensor(1);
|
||||
show_sensor(2);
|
||||
show_sensor(3);
|
||||
show_sensor(4);
|
||||
show_sensor(5);
|
||||
show_sensor(6);
|
||||
show_sensor(7);
|
||||
show_sensor(8); /* should be MAX_INTERFACES - 1 */
|
||||
|
||||
static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct phidget_interfacekit *kit;
|
||||
struct driver_interfacekit *ifkit;
|
||||
int pipe, maxp;
|
||||
|
||||
ifkit = (struct driver_interfacekit *)id->driver_info;
|
||||
if (!ifkit)
|
||||
return -ENODEV;
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
if (interface->desc.bNumEndpoints != 1)
|
||||
return -ENODEV;
|
||||
|
||||
endpoint = &interface->endpoint[0].desc;
|
||||
if (!(endpoint->bEndpointAddress & 0x80))
|
||||
return -ENODEV;
|
||||
/*
|
||||
* bmAttributes
|
||||
*/
|
||||
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
|
||||
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
|
||||
|
||||
kit = kmalloc(sizeof(*kit), GFP_KERNEL);
|
||||
if (kit == NULL) {
|
||||
dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(kit, 0, sizeof(*kit));
|
||||
kit->ifkit = ifkit;
|
||||
|
||||
kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
|
||||
if (!kit->data) {
|
||||
kfree(kit);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kit->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!kit->irq) {
|
||||
usb_buffer_free(dev, 8, kit->data, kit->data_dma);
|
||||
kfree(kit);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kit->udev = usb_get_dev(dev);
|
||||
kit->intf = intf;
|
||||
usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
|
||||
(maxp > 8 ? 8 : maxp),
|
||||
interfacekit_irq, kit, endpoint->bInterval);
|
||||
kit->irq->transfer_dma = kit->data_dma;
|
||||
kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
usb_set_intfdata(intf, kit);
|
||||
|
||||
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ifkit->outputs >= 4) {
|
||||
device_create_file(&intf->dev, &dev_attr_output1);
|
||||
device_create_file(&intf->dev, &dev_attr_output2);
|
||||
device_create_file(&intf->dev, &dev_attr_output3);
|
||||
device_create_file(&intf->dev, &dev_attr_output4);
|
||||
}
|
||||
if (ifkit->outputs == 8) {
|
||||
device_create_file(&intf->dev, &dev_attr_output5);
|
||||
device_create_file(&intf->dev, &dev_attr_output6);
|
||||
device_create_file(&intf->dev, &dev_attr_output7);
|
||||
device_create_file(&intf->dev, &dev_attr_output8);
|
||||
}
|
||||
|
||||
if (ifkit->inputs >= 4) {
|
||||
device_create_file(&intf->dev, &dev_attr_input1);
|
||||
device_create_file(&intf->dev, &dev_attr_input2);
|
||||
device_create_file(&intf->dev, &dev_attr_input3);
|
||||
device_create_file(&intf->dev, &dev_attr_input4);
|
||||
}
|
||||
if (ifkit->inputs == 8) {
|
||||
device_create_file(&intf->dev, &dev_attr_input5);
|
||||
device_create_file(&intf->dev, &dev_attr_input6);
|
||||
device_create_file(&intf->dev, &dev_attr_input7);
|
||||
device_create_file(&intf->dev, &dev_attr_input8);
|
||||
}
|
||||
|
||||
if (ifkit->sensors >= 4) {
|
||||
device_create_file(&intf->dev, &dev_attr_sensor1);
|
||||
device_create_file(&intf->dev, &dev_attr_sensor2);
|
||||
device_create_file(&intf->dev, &dev_attr_sensor3);
|
||||
device_create_file(&intf->dev, &dev_attr_sensor4);
|
||||
}
|
||||
if (ifkit->sensors >= 7) {
|
||||
device_create_file(&intf->dev, &dev_attr_sensor5);
|
||||
device_create_file(&intf->dev, &dev_attr_sensor6);
|
||||
device_create_file(&intf->dev, &dev_attr_sensor7);
|
||||
}
|
||||
if (ifkit->sensors == 8) {
|
||||
device_create_file(&intf->dev, &dev_attr_sensor8);
|
||||
}
|
||||
|
||||
if (ifkit->has_lcd)
|
||||
device_create_file(&intf->dev, &dev_attr_lcd);
|
||||
|
||||
dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
|
||||
ifkit->sensors, ifkit->inputs, ifkit->outputs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void interfacekit_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct phidget_interfacekit *kit;
|
||||
|
||||
kit = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
if (!kit)
|
||||
return;
|
||||
|
||||
if (kit->ifkit->outputs >= 4) {
|
||||
device_remove_file(&interface->dev, &dev_attr_output1);
|
||||
device_remove_file(&interface->dev, &dev_attr_output2);
|
||||
device_remove_file(&interface->dev, &dev_attr_output3);
|
||||
device_remove_file(&interface->dev, &dev_attr_output4);
|
||||
}
|
||||
if (kit->ifkit->outputs == 8) {
|
||||
device_remove_file(&interface->dev, &dev_attr_output5);
|
||||
device_remove_file(&interface->dev, &dev_attr_output6);
|
||||
device_remove_file(&interface->dev, &dev_attr_output7);
|
||||
device_remove_file(&interface->dev, &dev_attr_output8);
|
||||
}
|
||||
|
||||
if (kit->ifkit->inputs >= 4) {
|
||||
device_remove_file(&interface->dev, &dev_attr_input1);
|
||||
device_remove_file(&interface->dev, &dev_attr_input2);
|
||||
device_remove_file(&interface->dev, &dev_attr_input3);
|
||||
device_remove_file(&interface->dev, &dev_attr_input4);
|
||||
}
|
||||
if (kit->ifkit->inputs == 8) {
|
||||
device_remove_file(&interface->dev, &dev_attr_input5);
|
||||
device_remove_file(&interface->dev, &dev_attr_input6);
|
||||
device_remove_file(&interface->dev, &dev_attr_input7);
|
||||
device_remove_file(&interface->dev, &dev_attr_input8);
|
||||
}
|
||||
|
||||
if (kit->ifkit->sensors >= 4) {
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor1);
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor2);
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor3);
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor4);
|
||||
}
|
||||
if (kit->ifkit->sensors >= 7) {
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor5);
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor6);
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor7);
|
||||
}
|
||||
if (kit->ifkit->sensors == 8) {
|
||||
device_remove_file(&interface->dev, &dev_attr_sensor8);
|
||||
}
|
||||
if (kit->ifkit->has_lcd)
|
||||
device_remove_file(&interface->dev, &dev_attr_lcd);
|
||||
|
||||
dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
|
||||
kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
|
||||
|
||||
usb_kill_urb(kit->irq);
|
||||
usb_free_urb(kit->irq);
|
||||
usb_buffer_free(kit->udev, 8, kit->data, kit->data_dma);
|
||||
|
||||
usb_put_dev(kit->udev);
|
||||
kfree(kit);
|
||||
}
|
||||
|
||||
static struct usb_driver interfacekit_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "phidgetkit",
|
||||
.probe = interfacekit_probe,
|
||||
.disconnect = interfacekit_disconnect,
|
||||
.id_table = id_table
|
||||
};
|
||||
|
||||
static int __init interfacekit_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
retval = usb_register(&interfacekit_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit interfacekit_exit(void)
|
||||
{
|
||||
usb_deregister(&interfacekit_driver);
|
||||
}
|
||||
|
||||
module_init(interfacekit_init);
|
||||
module_exit(interfacekit_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
342
drivers/usb/misc/phidgetservo.c
Normal file
342
drivers/usb/misc/phidgetservo.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* USB PhidgetServo driver 1.0
|
||||
*
|
||||
* Copyright (C) 2004 Sean Young <sean@mess.org>
|
||||
*
|
||||
* 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 is a driver for the USB PhidgetServo version 2.0 and 3.0 servo
|
||||
* controllers available at: http://www.phidgets.com/
|
||||
*
|
||||
* Note that the driver takes input as: degrees.minutes
|
||||
*
|
||||
* CAUTION: Generally you should use 0 < degrees < 180 as anything else
|
||||
* is probably beyond the range of your servo and may damage it.
|
||||
*
|
||||
* Jun 16, 2004: Sean Young <sean@mess.org>
|
||||
* - cleanups
|
||||
* - was using memory after kfree()
|
||||
* Aug 8, 2004: Sean Young <sean@mess.org>
|
||||
* - set the highest angle as high as the hardware allows, there are
|
||||
* some odd servos out there
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
|
||||
#define DRIVER_DESC "USB PhidgetServo Driver"
|
||||
|
||||
#define VENDOR_ID_GLAB 0x06c2
|
||||
#define DEVICE_ID_GLAB_PHIDGETSERVO_QUAD 0x0038
|
||||
#define DEVICE_ID_GLAB_PHIDGETSERVO_UNI 0x0039
|
||||
|
||||
#define VENDOR_ID_WISEGROUP 0x0925
|
||||
#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD 0x8101
|
||||
#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI 0x8104
|
||||
|
||||
#define SERVO_VERSION_30 0x01
|
||||
#define SERVO_COUNT_QUAD 0x02
|
||||
|
||||
static struct usb_device_id id_table[] = {
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_QUAD),
|
||||
.driver_info = SERVO_VERSION_30 | SERVO_COUNT_QUAD
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_UNI),
|
||||
.driver_info = SERVO_VERSION_30
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_WISEGROUP,
|
||||
VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD),
|
||||
.driver_info = SERVO_COUNT_QUAD
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_WISEGROUP,
|
||||
VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI),
|
||||
.driver_info = 0
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
struct phidget_servo {
|
||||
struct usb_device *udev;
|
||||
ulong type;
|
||||
int pulse[4];
|
||||
int degrees[4];
|
||||
int minutes[4];
|
||||
};
|
||||
|
||||
static int
|
||||
change_position_v30(struct phidget_servo *servo, int servo_no, int degrees,
|
||||
int minutes)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
if (degrees < -23 || degrees > 362)
|
||||
return -EINVAL;
|
||||
|
||||
buffer = kmalloc(6, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&servo->udev->dev, "%s - out of memory\n",
|
||||
__FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* pulse = 0 - 4095
|
||||
* angle = 0 - 180 degrees
|
||||
*
|
||||
* pulse = angle * 10.6 + 243.8
|
||||
*/
|
||||
servo->pulse[servo_no] = ((degrees*60 + minutes)*106 + 2438*60)/600;
|
||||
servo->degrees[servo_no]= degrees;
|
||||
servo->minutes[servo_no]= minutes;
|
||||
|
||||
/*
|
||||
* The PhidgetServo v3.0 is controlled by sending 6 bytes,
|
||||
* 4 * 12 bits for each servo.
|
||||
*
|
||||
* low = lower 8 bits pulse
|
||||
* high = higher 4 bits pulse
|
||||
*
|
||||
* offset bits
|
||||
* +---+-----------------+
|
||||
* | 0 | low 0 |
|
||||
* +---+--------+--------+
|
||||
* | 1 | high 1 | high 0 |
|
||||
* +---+--------+--------+
|
||||
* | 2 | low 1 |
|
||||
* +---+-----------------+
|
||||
* | 3 | low 2 |
|
||||
* +---+--------+--------+
|
||||
* | 4 | high 3 | high 2 |
|
||||
* +---+--------+--------+
|
||||
* | 5 | low 3 |
|
||||
* +---+-----------------+
|
||||
*/
|
||||
|
||||
buffer[0] = servo->pulse[0] & 0xff;
|
||||
buffer[1] = (servo->pulse[0] >> 8 & 0x0f)
|
||||
| (servo->pulse[1] >> 4 & 0xf0);
|
||||
buffer[2] = servo->pulse[1] & 0xff;
|
||||
buffer[3] = servo->pulse[2] & 0xff;
|
||||
buffer[4] = (servo->pulse[2] >> 8 & 0x0f)
|
||||
| (servo->pulse[3] >> 4 & 0xf0);
|
||||
buffer[5] = servo->pulse[3] & 0xff;
|
||||
|
||||
dev_dbg(&servo->udev->dev,
|
||||
"data: %02x %02x %02x %02x %02x %02x\n",
|
||||
buffer[0], buffer[1], buffer[2],
|
||||
buffer[3], buffer[4], buffer[5]);
|
||||
|
||||
retval = usb_control_msg(servo->udev,
|
||||
usb_sndctrlpipe(servo->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2000);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
|
||||
int minutes)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
if (degrees < -23 || degrees > 278)
|
||||
return -EINVAL;
|
||||
|
||||
buffer = kmalloc(2, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&servo->udev->dev, "%s - out of memory\n",
|
||||
__FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* angle = 0 - 180 degrees
|
||||
* pulse = angle + 23
|
||||
*/
|
||||
servo->pulse[servo_no]= degrees + 23;
|
||||
servo->degrees[servo_no]= degrees;
|
||||
servo->minutes[servo_no]= 0;
|
||||
|
||||
/*
|
||||
* The PhidgetServo v2.0 is controlled by sending two bytes. The
|
||||
* first byte is the servo number xor'ed with 2:
|
||||
*
|
||||
* servo 0 = 2
|
||||
* servo 1 = 3
|
||||
* servo 2 = 0
|
||||
* servo 3 = 1
|
||||
*
|
||||
* The second byte is the position.
|
||||
*/
|
||||
|
||||
buffer[0] = servo_no ^ 2;
|
||||
buffer[1] = servo->pulse[servo_no];
|
||||
|
||||
dev_dbg(&servo->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
|
||||
|
||||
retval = usb_control_msg(servo->udev,
|
||||
usb_sndctrlpipe(servo->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2000);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define show_set(value) \
|
||||
static ssize_t set_servo##value (struct device *dev, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
int degrees, minutes, retval; \
|
||||
struct usb_interface *intf = to_usb_interface (dev); \
|
||||
struct phidget_servo *servo = usb_get_intfdata (intf); \
|
||||
\
|
||||
minutes = 0; \
|
||||
/* must at least convert degrees */ \
|
||||
if (sscanf (buf, "%d.%d", °rees, &minutes) < 1) { \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (minutes < 0 || minutes > 59) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (servo->type & SERVO_VERSION_30) \
|
||||
retval = change_position_v30 (servo, value, degrees, \
|
||||
minutes); \
|
||||
else \
|
||||
retval = change_position_v20 (servo, value, degrees, \
|
||||
minutes); \
|
||||
\
|
||||
return retval < 0 ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_servo##value (struct device *dev, char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface (dev); \
|
||||
struct phidget_servo *servo = usb_get_intfdata (intf); \
|
||||
\
|
||||
return sprintf (buf, "%d.%02d\n", servo->degrees[value], \
|
||||
servo->minutes[value]); \
|
||||
} \
|
||||
static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
|
||||
show_servo##value, set_servo##value);
|
||||
|
||||
show_set(0);
|
||||
show_set(1);
|
||||
show_set(2);
|
||||
show_set(3);
|
||||
|
||||
static int
|
||||
servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct phidget_servo *dev;
|
||||
|
||||
dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(dev, 0x00, sizeof (*dev));
|
||||
|
||||
dev->udev = usb_get_dev(udev);
|
||||
dev->type = id->driver_info;
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
device_create_file(&interface->dev, &dev_attr_servo0);
|
||||
if (dev->type & SERVO_COUNT_QUAD) {
|
||||
device_create_file(&interface->dev, &dev_attr_servo1);
|
||||
device_create_file(&interface->dev, &dev_attr_servo2);
|
||||
device_create_file(&interface->dev, &dev_attr_servo3);
|
||||
}
|
||||
|
||||
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
|
||||
dev->type & SERVO_COUNT_QUAD ? 4 : 1,
|
||||
dev->type & SERVO_VERSION_30 ? 3 : 2);
|
||||
|
||||
if(!(dev->type & SERVO_VERSION_30))
|
||||
dev_info(&interface->dev,
|
||||
"WARNING: v2.0 not tested! Please report if it works.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
servo_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct phidget_servo *dev;
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
device_remove_file(&interface->dev, &dev_attr_servo0);
|
||||
if (dev->type & SERVO_COUNT_QUAD) {
|
||||
device_remove_file(&interface->dev, &dev_attr_servo1);
|
||||
device_remove_file(&interface->dev, &dev_attr_servo2);
|
||||
device_remove_file(&interface->dev, &dev_attr_servo3);
|
||||
}
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
|
||||
dev->type & SERVO_COUNT_QUAD ? 4 : 1,
|
||||
dev->type & SERVO_VERSION_30 ? 3 : 2);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct usb_driver servo_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "phidgetservo",
|
||||
.probe = servo_probe,
|
||||
.disconnect = servo_disconnect,
|
||||
.id_table = id_table
|
||||
};
|
||||
|
||||
static int __init
|
||||
phidget_servo_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = usb_register(&servo_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
phidget_servo_exit(void)
|
||||
{
|
||||
usb_deregister(&servo_driver);
|
||||
}
|
||||
|
||||
module_init(phidget_servo_init);
|
||||
module_exit(phidget_servo_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
563
drivers/usb/misc/rio500.c
Normal file
563
drivers/usb/misc/rio500.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/* -*- linux-c -*- */
|
||||
|
||||
/*
|
||||
* Driver for USB Rio 500
|
||||
*
|
||||
* Cesar Miquel (miquel@df.uba.ar)
|
||||
*
|
||||
* based on hp_scanner.c by David E. Nelson (dnelson@jump.net)
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
|
||||
*
|
||||
* Changelog:
|
||||
* 30/05/2003 replaced lock/unlock kernel with up/down
|
||||
* Daniele Bellucci bellucda@tiscali.it
|
||||
* */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "rio500_usb.h"
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v1.1"
|
||||
#define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
|
||||
#define DRIVER_DESC "USB Rio 500 driver"
|
||||
|
||||
#define RIO_MINOR 64
|
||||
|
||||
/* stall/wait timeout for rio */
|
||||
#define NAK_TIMEOUT (HZ)
|
||||
|
||||
#define IBUF_SIZE 0x1000
|
||||
|
||||
/* Size of the rio buffer */
|
||||
#define OBUF_SIZE 0x10000
|
||||
|
||||
struct rio_usb_data {
|
||||
struct usb_device *rio_dev; /* init: probe_rio */
|
||||
unsigned int ifnum; /* Interface number of the USB device */
|
||||
int isopen; /* nz if open */
|
||||
int present; /* Device is present on the bus */
|
||||
char *obuf, *ibuf; /* transfer buffers */
|
||||
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
|
||||
wait_queue_head_t wait_q; /* for timeouts */
|
||||
struct semaphore lock; /* general race avoidance */
|
||||
};
|
||||
|
||||
static struct rio_usb_data rio_instance;
|
||||
|
||||
static int open_rio(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
|
||||
down(&(rio->lock));
|
||||
|
||||
if (rio->isopen || !rio->present) {
|
||||
up(&(rio->lock));
|
||||
return -EBUSY;
|
||||
}
|
||||
rio->isopen = 1;
|
||||
|
||||
init_waitqueue_head(&rio->wait_q);
|
||||
|
||||
up(&(rio->lock));
|
||||
|
||||
info("Rio opened.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int close_rio(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
|
||||
rio->isopen = 0;
|
||||
|
||||
info("Rio closed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct RioCommand rio_cmd;
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
void __user *data;
|
||||
unsigned char *buffer;
|
||||
int result, requesttype;
|
||||
int retries;
|
||||
int retval=0;
|
||||
|
||||
down(&(rio->lock));
|
||||
/* Sanity check to make sure rio is connected, powered, etc */
|
||||
if ( rio == NULL ||
|
||||
rio->present == 0 ||
|
||||
rio->rio_dev == NULL )
|
||||
{
|
||||
retval = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case RIO_RECV_COMMAND:
|
||||
data = (void __user *) arg;
|
||||
if (data == NULL)
|
||||
break;
|
||||
if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
|
||||
retval = -EFAULT;
|
||||
goto err_out;
|
||||
}
|
||||
if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
|
||||
retval = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
|
||||
if (buffer == NULL) {
|
||||
retval = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
|
||||
retval = -EFAULT;
|
||||
free_page((unsigned long) buffer);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
requesttype = rio_cmd.requesttype | USB_DIR_IN |
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
|
||||
dbg
|
||||
("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
|
||||
requesttype, rio_cmd.request, rio_cmd.value,
|
||||
rio_cmd.index, rio_cmd.length);
|
||||
/* Send rio control message */
|
||||
retries = 3;
|
||||
while (retries) {
|
||||
result = usb_control_msg(rio->rio_dev,
|
||||
usb_rcvctrlpipe(rio-> rio_dev, 0),
|
||||
rio_cmd.request,
|
||||
requesttype,
|
||||
rio_cmd.value,
|
||||
rio_cmd.index, buffer,
|
||||
rio_cmd.length,
|
||||
jiffies_to_msecs(rio_cmd.timeout));
|
||||
if (result == -ETIMEDOUT)
|
||||
retries--;
|
||||
else if (result < 0) {
|
||||
err("Error executing ioctrl. code = %d", result);
|
||||
retries = 0;
|
||||
} else {
|
||||
dbg("Executed ioctl. Result = %d (data=%02x)",
|
||||
result, buffer[0]);
|
||||
if (copy_to_user(rio_cmd.buffer, buffer,
|
||||
rio_cmd.length)) {
|
||||
free_page((unsigned long) buffer);
|
||||
retval = -EFAULT;
|
||||
goto err_out;
|
||||
}
|
||||
retries = 0;
|
||||
}
|
||||
|
||||
/* rio_cmd.buffer contains a raw stream of single byte
|
||||
data which has been returned from rio. Data is
|
||||
interpreted at application level. For data that
|
||||
will be cast to data types longer than 1 byte, data
|
||||
will be little_endian and will potentially need to
|
||||
be swapped at the app level */
|
||||
|
||||
}
|
||||
free_page((unsigned long) buffer);
|
||||
break;
|
||||
|
||||
case RIO_SEND_COMMAND:
|
||||
data = (void __user *) arg;
|
||||
if (data == NULL)
|
||||
break;
|
||||
if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
|
||||
retval = -EFAULT;
|
||||
goto err_out;
|
||||
}
|
||||
if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
|
||||
retval = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
|
||||
if (buffer == NULL) {
|
||||
retval = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
|
||||
free_page((unsigned long)buffer);
|
||||
retval = -EFAULT;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
requesttype = rio_cmd.requesttype | USB_DIR_OUT |
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
|
||||
dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
|
||||
requesttype, rio_cmd.request, rio_cmd.value,
|
||||
rio_cmd.index, rio_cmd.length);
|
||||
/* Send rio control message */
|
||||
retries = 3;
|
||||
while (retries) {
|
||||
result = usb_control_msg(rio->rio_dev,
|
||||
usb_sndctrlpipe(rio-> rio_dev, 0),
|
||||
rio_cmd.request,
|
||||
requesttype,
|
||||
rio_cmd.value,
|
||||
rio_cmd.index, buffer,
|
||||
rio_cmd.length,
|
||||
jiffies_to_msecs(rio_cmd.timeout));
|
||||
if (result == -ETIMEDOUT)
|
||||
retries--;
|
||||
else if (result < 0) {
|
||||
err("Error executing ioctrl. code = %d", result);
|
||||
retries = 0;
|
||||
} else {
|
||||
dbg("Executed ioctl. Result = %d", result);
|
||||
retries = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
free_page((unsigned long) buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
err_out:
|
||||
up(&(rio->lock));
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
write_rio(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t * ppos)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
|
||||
unsigned long copy_size;
|
||||
unsigned long bytes_written = 0;
|
||||
unsigned int partial;
|
||||
|
||||
int result = 0;
|
||||
int maxretry;
|
||||
int errn = 0;
|
||||
|
||||
down(&(rio->lock));
|
||||
/* Sanity check to make sure rio is connected, powered, etc */
|
||||
if ( rio == NULL ||
|
||||
rio->present == 0 ||
|
||||
rio->rio_dev == NULL )
|
||||
{
|
||||
up(&(rio->lock));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
|
||||
do {
|
||||
unsigned long thistime;
|
||||
char *obuf = rio->obuf;
|
||||
|
||||
thistime = copy_size =
|
||||
(count >= OBUF_SIZE) ? OBUF_SIZE : count;
|
||||
if (copy_from_user(rio->obuf, buffer, copy_size)) {
|
||||
errn = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
maxretry = 5;
|
||||
while (thistime) {
|
||||
if (!rio->rio_dev) {
|
||||
errn = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
up(&(rio->lock));
|
||||
return bytes_written ? bytes_written : -EINTR;
|
||||
}
|
||||
|
||||
result = usb_bulk_msg(rio->rio_dev,
|
||||
usb_sndbulkpipe(rio->rio_dev, 2),
|
||||
obuf, thistime, &partial, 5000);
|
||||
|
||||
dbg("write stats: result:%d thistime:%lu partial:%u",
|
||||
result, thistime, partial);
|
||||
|
||||
if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
|
||||
if (!maxretry--) {
|
||||
errn = -ETIME;
|
||||
goto error;
|
||||
}
|
||||
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(NAK_TIMEOUT);
|
||||
finish_wait(&rio->wait_q, &wait);
|
||||
continue;
|
||||
} else if (!result && partial) {
|
||||
obuf += partial;
|
||||
thistime -= partial;
|
||||
} else
|
||||
break;
|
||||
};
|
||||
if (result) {
|
||||
err("Write Whoops - %x", result);
|
||||
errn = -EIO;
|
||||
goto error;
|
||||
}
|
||||
bytes_written += copy_size;
|
||||
count -= copy_size;
|
||||
buffer += copy_size;
|
||||
} while (count > 0);
|
||||
|
||||
up(&(rio->lock));
|
||||
|
||||
return bytes_written ? bytes_written : -EIO;
|
||||
|
||||
error:
|
||||
up(&(rio->lock));
|
||||
return errn;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
ssize_t read_count;
|
||||
unsigned int partial;
|
||||
int this_read;
|
||||
int result;
|
||||
int maxretry = 10;
|
||||
char *ibuf;
|
||||
|
||||
down(&(rio->lock));
|
||||
/* Sanity check to make sure rio is connected, powered, etc */
|
||||
if ( rio == NULL ||
|
||||
rio->present == 0 ||
|
||||
rio->rio_dev == NULL )
|
||||
{
|
||||
up(&(rio->lock));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ibuf = rio->ibuf;
|
||||
|
||||
read_count = 0;
|
||||
|
||||
|
||||
while (count > 0) {
|
||||
if (signal_pending(current)) {
|
||||
up(&(rio->lock));
|
||||
return read_count ? read_count : -EINTR;
|
||||
}
|
||||
if (!rio->rio_dev) {
|
||||
up(&(rio->lock));
|
||||
return -ENODEV;
|
||||
}
|
||||
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
|
||||
|
||||
result = usb_bulk_msg(rio->rio_dev,
|
||||
usb_rcvbulkpipe(rio->rio_dev, 1),
|
||||
ibuf, this_read, &partial,
|
||||
8000);
|
||||
|
||||
dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
|
||||
result, this_read, partial);
|
||||
|
||||
if (partial) {
|
||||
count = this_read = partial;
|
||||
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
|
||||
if (!maxretry--) {
|
||||
up(&(rio->lock));
|
||||
err("read_rio: maxretry timeout");
|
||||
return -ETIME;
|
||||
}
|
||||
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(NAK_TIMEOUT);
|
||||
finish_wait(&rio->wait_q, &wait);
|
||||
continue;
|
||||
} else if (result != -EREMOTEIO) {
|
||||
up(&(rio->lock));
|
||||
err("Read Whoops - result:%u partial:%u this_read:%u",
|
||||
result, partial, this_read);
|
||||
return -EIO;
|
||||
} else {
|
||||
up(&(rio->lock));
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (this_read) {
|
||||
if (copy_to_user(buffer, ibuf, this_read)) {
|
||||
up(&(rio->lock));
|
||||
return -EFAULT;
|
||||
}
|
||||
count -= this_read;
|
||||
read_count += this_read;
|
||||
buffer += this_read;
|
||||
}
|
||||
}
|
||||
up(&(rio->lock));
|
||||
return read_count;
|
||||
}
|
||||
|
||||
static struct
|
||||
file_operations usb_rio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = read_rio,
|
||||
.write = write_rio,
|
||||
.ioctl = ioctl_rio,
|
||||
.open = open_rio,
|
||||
.release = close_rio,
|
||||
};
|
||||
|
||||
static struct usb_class_driver usb_rio_class = {
|
||||
.name = "usb/rio500%d",
|
||||
.fops = &usb_rio_fops,
|
||||
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
|
||||
.minor_base = RIO_MINOR,
|
||||
};
|
||||
|
||||
static int probe_rio(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
int retval;
|
||||
|
||||
info("USB Rio found at address %d", dev->devnum);
|
||||
|
||||
retval = usb_register_dev(intf, &usb_rio_class);
|
||||
if (retval) {
|
||||
err("Not able to get a minor for this device.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rio->rio_dev = dev;
|
||||
|
||||
if (!(rio->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
|
||||
err("probe_rio: Not enough memory for the output buffer");
|
||||
usb_deregister_dev(intf, &usb_rio_class);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dbg("probe_rio: obuf address:%p", rio->obuf);
|
||||
|
||||
if (!(rio->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
|
||||
err("probe_rio: Not enough memory for the input buffer");
|
||||
usb_deregister_dev(intf, &usb_rio_class);
|
||||
kfree(rio->obuf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dbg("probe_rio: ibuf address:%p", rio->ibuf);
|
||||
|
||||
init_MUTEX(&(rio->lock));
|
||||
|
||||
usb_set_intfdata (intf, rio);
|
||||
rio->present = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disconnect_rio(struct usb_interface *intf)
|
||||
{
|
||||
struct rio_usb_data *rio = usb_get_intfdata (intf);
|
||||
|
||||
usb_set_intfdata (intf, NULL);
|
||||
if (rio) {
|
||||
usb_deregister_dev(intf, &usb_rio_class);
|
||||
|
||||
down(&(rio->lock));
|
||||
if (rio->isopen) {
|
||||
rio->isopen = 0;
|
||||
/* better let it finish - the release will do whats needed */
|
||||
rio->rio_dev = NULL;
|
||||
up(&(rio->lock));
|
||||
return;
|
||||
}
|
||||
kfree(rio->ibuf);
|
||||
kfree(rio->obuf);
|
||||
|
||||
info("USB Rio disconnected.");
|
||||
|
||||
rio->present = 0;
|
||||
up(&(rio->lock));
|
||||
}
|
||||
}
|
||||
|
||||
static struct usb_device_id rio_table [] = {
|
||||
{ USB_DEVICE(0x0841, 1) }, /* Rio 500 */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, rio_table);
|
||||
|
||||
static struct usb_driver rio_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "rio500",
|
||||
.probe = probe_rio,
|
||||
.disconnect = disconnect_rio,
|
||||
.id_table = rio_table,
|
||||
};
|
||||
|
||||
static int __init usb_rio_init(void)
|
||||
{
|
||||
int retval;
|
||||
retval = usb_register(&rio_driver);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
info(DRIVER_VERSION ":" DRIVER_DESC);
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void __exit usb_rio_cleanup(void)
|
||||
{
|
||||
struct rio_usb_data *rio = &rio_instance;
|
||||
|
||||
rio->present = 0;
|
||||
usb_deregister(&rio_driver);
|
||||
|
||||
|
||||
}
|
||||
|
||||
module_init(usb_rio_init);
|
||||
module_exit(usb_rio_cleanup);
|
||||
|
||||
MODULE_AUTHOR( DRIVER_AUTHOR );
|
||||
MODULE_DESCRIPTION( DRIVER_DESC );
|
||||
MODULE_LICENSE("GPL");
|
||||
|
37
drivers/usb/misc/rio500_usb.h
Normal file
37
drivers/usb/misc/rio500_usb.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2000 Cesar Miquel (miquel@df.uba.ar)
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
#define RIO_SEND_COMMAND 0x1
|
||||
#define RIO_RECV_COMMAND 0x2
|
||||
|
||||
#define RIO_DIR_OUT 0x0
|
||||
#define RIO_DIR_IN 0x1
|
||||
|
||||
struct RioCommand {
|
||||
short length;
|
||||
int request;
|
||||
int requesttype;
|
||||
int value;
|
||||
int index;
|
||||
void __user *buffer;
|
||||
int timeout;
|
||||
};
|
14
drivers/usb/misc/sisusbvga/Kconfig
Normal file
14
drivers/usb/misc/sisusbvga/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
config USB_SISUSBVGA
|
||||
tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
|
||||
depends on USB && USB_EHCI_HCD
|
||||
---help---
|
||||
Say Y here if you intend to attach a USB2VGA dongle based on a
|
||||
Net2280 and a SiS315 chip.
|
||||
|
||||
Note that this device requires a USB 2.0 host controller. It will not
|
||||
work with USB 1.x controllers.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called sisusb. If unsure, say N.
|
||||
|
6
drivers/usb/misc/sisusbvga/Makefile
Normal file
6
drivers/usb/misc/sisusbvga/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# Makefile for the sisusb driver (if driver is inside kernel tree).
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
|
||||
|
3145
drivers/usb/misc/sisusbvga/sisusb.c
Normal file
3145
drivers/usb/misc/sisusbvga/sisusb.c
Normal file
文件差異過大導致無法顯示
Load Diff
278
drivers/usb/misc/sisusbvga/sisusb.h
Normal file
278
drivers/usb/misc/sisusbvga/sisusb.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles
|
||||
*
|
||||
* Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
|
||||
*
|
||||
* If distributed as part of the Linux kernel, this code is licensed under the
|
||||
* terms of the GPL v2.
|
||||
*
|
||||
* Otherwise, the following license terms apply:
|
||||
*
|
||||
* * Redistribution and use in source and binary forms, with or without
|
||||
* * modification, are permitted provided that the following conditions
|
||||
* * are met:
|
||||
* * 1) Redistributions of source code must retain the above copyright
|
||||
* * notice, this list of conditions and the following disclaimer.
|
||||
* * 2) Redistributions in binary form must reproduce the above copyright
|
||||
* * notice, this list of conditions and the following disclaimer in the
|
||||
* * documentation and/or other materials provided with the distribution.
|
||||
* * 3) The name of the author may not be used to endorse or promote products
|
||||
* * derived from this software without specific prior written permission.
|
||||
* *
|
||||
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
||||
* * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Thomas Winischhofer <thomas@winischhofer.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SISUSB_H_
|
||||
#define _SISUSB_H_
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
|
||||
#include <linux/ioctl32.h>
|
||||
#define SISUSB_OLD_CONFIG_COMPAT
|
||||
#else
|
||||
#define SISUSB_NEW_CONFIG_COMPAT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Version Information */
|
||||
|
||||
#define SISUSB_VERSION 0
|
||||
#define SISUSB_REVISION 0
|
||||
#define SISUSB_PATCHLEVEL 7
|
||||
|
||||
/* USB related */
|
||||
|
||||
#define SISUSB_MINOR 133 /* FIXME */
|
||||
|
||||
/* Size of the sisusb input/output buffers */
|
||||
#define SISUSB_IBUF_SIZE 0x01000
|
||||
#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
|
||||
|
||||
#define NUMOBUFS 8 /* max number of output buffers/output URBs */
|
||||
|
||||
/* About endianness:
|
||||
*
|
||||
* 1) I/O ports, PCI config registers. The read/write()
|
||||
* calls emulate inX/outX. Hence, the data is
|
||||
* expected/delivered in machine endiannes by this
|
||||
* driver.
|
||||
* 2) Video memory. The data is copied 1:1. There is
|
||||
* no swapping. Ever. This means for userland that
|
||||
* the data has to be prepared properly. (Hint:
|
||||
* think graphics data format, command queue,
|
||||
* hardware cursor.)
|
||||
* 3) MMIO. Data is copied 1:1. MMIO must be swapped
|
||||
* properly by userland.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
|
||||
do { \
|
||||
p->header = cpu_to_le16(p->header); \
|
||||
p->address = cpu_to_le32(p->address); \
|
||||
p->data = cpu_to_le32(p->data); \
|
||||
} while(0)
|
||||
#else
|
||||
#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)
|
||||
#endif
|
||||
|
||||
struct sisusb_usb_data;
|
||||
|
||||
struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
|
||||
struct sisusb_usb_data *sisusb;
|
||||
int urbindex;
|
||||
int *actual_length;
|
||||
};
|
||||
|
||||
struct sisusb_usb_data {
|
||||
struct usb_device *sisusb_dev;
|
||||
struct usb_interface *interface;
|
||||
struct kref kref;
|
||||
wait_queue_head_t wait_q; /* for syncind and timeouts */
|
||||
struct semaphore lock; /* general race avoidance */
|
||||
unsigned int ifnum; /* interface number of the USB device */
|
||||
int minor; /* minor (for logging clarity) */
|
||||
int isopen; /* !=0 if open */
|
||||
int present; /* !=0 if device is present on the bus */
|
||||
int ready; /* !=0 if device is ready for userland */
|
||||
#ifdef SISUSB_OLD_CONFIG_COMPAT
|
||||
int ioctl32registered;
|
||||
#endif
|
||||
int numobufs; /* number of obufs = number of out urbs */
|
||||
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
|
||||
int obufsize, ibufsize;
|
||||
dma_addr_t transfer_dma_out[NUMOBUFS];
|
||||
dma_addr_t transfer_dma_in;
|
||||
struct urb *sisurbout[NUMOBUFS];
|
||||
struct urb *sisurbin;
|
||||
unsigned char urbstatus[NUMOBUFS];
|
||||
unsigned char completein;
|
||||
struct sisusb_urb_context urbout_context[NUMOBUFS];
|
||||
unsigned long flagb0;
|
||||
unsigned long vrambase; /* framebuffer base */
|
||||
unsigned int vramsize; /* framebuffer size (bytes) */
|
||||
unsigned long mmiobase;
|
||||
unsigned int mmiosize;
|
||||
unsigned long ioportbase;
|
||||
unsigned char devinit; /* device initialized? */
|
||||
unsigned char gfxinit; /* graphics core initialized? */
|
||||
unsigned short chipid, chipvendor;
|
||||
unsigned short chiprevision;
|
||||
};
|
||||
|
||||
#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
|
||||
|
||||
/* USB transport related */
|
||||
|
||||
/* urbstatus */
|
||||
#define SU_URB_BUSY 1
|
||||
#define SU_URB_ALLOC 2
|
||||
|
||||
/* Endpoints */
|
||||
|
||||
#define SISUSB_EP_GFX_IN 0x0e /* gfx std packet out(0e)/in(8e) */
|
||||
#define SISUSB_EP_GFX_OUT 0x0e
|
||||
|
||||
#define SISUSB_EP_GFX_BULK_OUT 0x01 /* gfx mem bulk out/in */
|
||||
#define SISUSB_EP_GFX_BULK_IN 0x02 /* ? 2 is "OUT" ? */
|
||||
|
||||
#define SISUSB_EP_GFX_LBULK_OUT 0x03 /* gfx large mem bulk out */
|
||||
|
||||
#define SISUSB_EP_UNKNOWN_04 0x04 /* ? 4 is "OUT" ? - unused */
|
||||
|
||||
#define SISUSB_EP_BRIDGE_IN 0x0d /* Net2280 out(0d)/in(8d) */
|
||||
#define SISUSB_EP_BRIDGE_OUT 0x0d
|
||||
|
||||
#define SISUSB_TYPE_MEM 0
|
||||
#define SISUSB_TYPE_IO 1
|
||||
|
||||
struct sisusb_packet {
|
||||
unsigned short header;
|
||||
u32 address;
|
||||
u32 data;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define CLEARPACKET(packet) memset(packet, 0, 10)
|
||||
|
||||
/* PCI bridge related */
|
||||
|
||||
#define SISUSB_PCI_MEMBASE 0xd0000000
|
||||
#define SISUSB_PCI_MMIOBASE 0xe4000000
|
||||
#define SISUSB_PCI_IOPORTBASE 0x0000d000
|
||||
|
||||
#define SISUSB_PCI_PSEUDO_MEMBASE 0x10000000
|
||||
#define SISUSB_PCI_PSEUDO_MMIOBASE 0x20000000
|
||||
#define SISUSB_PCI_PSEUDO_IOPORTBASE 0x0000d000
|
||||
#define SISUSB_PCI_PSEUDO_PCIBASE 0x00010000
|
||||
|
||||
#define SISUSB_PCI_MMIOSIZE (128*1024)
|
||||
#define SISUSB_PCI_PCONFSIZE 0x5c
|
||||
|
||||
/* graphics core related */
|
||||
|
||||
#define AROFFSET 0x40
|
||||
#define ARROFFSET 0x41
|
||||
#define GROFFSET 0x4e
|
||||
#define SROFFSET 0x44
|
||||
#define CROFFSET 0x54
|
||||
#define MISCROFFSET 0x4c
|
||||
#define MISCWOFFSET 0x42
|
||||
#define INPUTSTATOFFSET 0x5A
|
||||
#define PART1OFFSET 0x04
|
||||
#define PART2OFFSET 0x10
|
||||
#define PART3OFFSET 0x12
|
||||
#define PART4OFFSET 0x14
|
||||
#define PART5OFFSET 0x16
|
||||
#define CAPTUREOFFSET 0x00
|
||||
#define VIDEOOFFSET 0x02
|
||||
#define COLREGOFFSET 0x48
|
||||
#define PELMASKOFFSET 0x46
|
||||
#define VGAENABLE 0x43
|
||||
|
||||
#define SISAR SISUSB_PCI_IOPORTBASE + AROFFSET
|
||||
#define SISARR SISUSB_PCI_IOPORTBASE + ARROFFSET
|
||||
#define SISGR SISUSB_PCI_IOPORTBASE + GROFFSET
|
||||
#define SISSR SISUSB_PCI_IOPORTBASE + SROFFSET
|
||||
#define SISCR SISUSB_PCI_IOPORTBASE + CROFFSET
|
||||
#define SISMISCR SISUSB_PCI_IOPORTBASE + MISCROFFSET
|
||||
#define SISMISCW SISUSB_PCI_IOPORTBASE + MISCWOFFSET
|
||||
#define SISINPSTAT SISUSB_PCI_IOPORTBASE + INPUTSTATOFFSET
|
||||
#define SISPART1 SISUSB_PCI_IOPORTBASE + PART1OFFSET
|
||||
#define SISPART2 SISUSB_PCI_IOPORTBASE + PART2OFFSET
|
||||
#define SISPART3 SISUSB_PCI_IOPORTBASE + PART3OFFSET
|
||||
#define SISPART4 SISUSB_PCI_IOPORTBASE + PART4OFFSET
|
||||
#define SISPART5 SISUSB_PCI_IOPORTBASE + PART5OFFSET
|
||||
#define SISCAP SISUSB_PCI_IOPORTBASE + CAPTUREOFFSET
|
||||
#define SISVID SISUSB_PCI_IOPORTBASE + VIDEOOFFSET
|
||||
#define SISCOLIDXR SISUSB_PCI_IOPORTBASE + COLREGOFFSET - 1
|
||||
#define SISCOLIDX SISUSB_PCI_IOPORTBASE + COLREGOFFSET
|
||||
#define SISCOLDATA SISUSB_PCI_IOPORTBASE + COLREGOFFSET + 1
|
||||
#define SISCOL2IDX SISPART5
|
||||
#define SISCOL2DATA SISPART5 + 1
|
||||
#define SISPEL SISUSB_PCI_IOPORTBASE + PELMASKOFFSET
|
||||
#define SISVGAEN SISUSB_PCI_IOPORTBASE + VGAENABLE
|
||||
#define SISDACA SISCOLIDX
|
||||
#define SISDACD SISCOLDATA
|
||||
|
||||
/* ioctl related */
|
||||
|
||||
/* Structure argument for SISUSB_GET_INFO ioctl */
|
||||
struct sisusb_info {
|
||||
__u32 sisusb_id; /* for identifying sisusb */
|
||||
#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
|
||||
__u8 sisusb_version;
|
||||
__u8 sisusb_revision;
|
||||
__u8 sisusb_patchlevel;
|
||||
__u8 sisusb_gfxinit; /* graphics core initialized? */
|
||||
|
||||
__u32 sisusb_vrambase;
|
||||
__u32 sisusb_mmiobase;
|
||||
__u32 sisusb_iobase;
|
||||
__u32 sisusb_pcibase;
|
||||
|
||||
__u32 sisusb_vramsize; /* framebuffer size in bytes */
|
||||
|
||||
__u32 sisusb_minor;
|
||||
|
||||
__u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
|
||||
|
||||
__u8 sisusb_reserved[32]; /* for future use */
|
||||
};
|
||||
|
||||
struct sisusb_command {
|
||||
__u8 operation; /* see below */
|
||||
__u8 data0; /* operation dependent */
|
||||
__u8 data1; /* operation dependent */
|
||||
__u8 data2; /* operation dependent */
|
||||
__u32 data3; /* operation dependent */
|
||||
__u32 data4; /* for future use */
|
||||
};
|
||||
|
||||
#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
|
||||
#define SUCMD_SET 0x02 /* data1 = value */
|
||||
#define SUCMD_SETOR 0x03 /* data1 = or */
|
||||
#define SUCMD_SETAND 0x04 /* data1 = and */
|
||||
#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */
|
||||
#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */
|
||||
|
||||
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
|
||||
|
||||
#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command)
|
||||
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
|
||||
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
|
||||
|
||||
#endif /* SISUSB_H */
|
||||
|
404
drivers/usb/misc/usblcd.c
Normal file
404
drivers/usb/misc/usblcd.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/*****************************************************************************
|
||||
* USBLCD Kernel Driver *
|
||||
* Version 1.05 *
|
||||
* (C) 2005 Georges Toth <g.toth@e-biz.lu> *
|
||||
* *
|
||||
* This file is licensed under the GPL. See COPYING in the package. *
|
||||
* Based on usb-skeleton.c 2.0 by Greg Kroah-Hartman (greg@kroah.com) *
|
||||
* *
|
||||
* *
|
||||
* 28.02.05 Complete rewrite of the original usblcd.c driver, *
|
||||
* based on usb_skeleton.c. *
|
||||
* This new driver allows more than one USB-LCD to be connected *
|
||||
* and controlled, at once *
|
||||
*****************************************************************************/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define DRIVER_VERSION "USBLCD Driver Version 1.05"
|
||||
|
||||
#define USBLCD_MINOR 144
|
||||
|
||||
#define IOCTL_GET_HARD_VERSION 1
|
||||
#define IOCTL_GET_DRV_VERSION 2
|
||||
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
||||
|
||||
struct usb_lcd {
|
||||
struct usb_device * udev; /* init: probe_lcd */
|
||||
struct usb_interface * interface; /* the interface for this device */
|
||||
unsigned char * bulk_in_buffer; /* the buffer to receive data */
|
||||
size_t bulk_in_size; /* the size of the receive buffer */
|
||||
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
|
||||
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
|
||||
struct kref kref;
|
||||
};
|
||||
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
|
||||
|
||||
static struct usb_driver lcd_driver;
|
||||
|
||||
|
||||
static void lcd_delete(struct kref *kref)
|
||||
{
|
||||
struct usb_lcd *dev = to_lcd_dev(kref);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
kfree (dev->bulk_in_buffer);
|
||||
kfree (dev);
|
||||
}
|
||||
|
||||
|
||||
static int lcd_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
struct usb_interface *interface;
|
||||
int subminor;
|
||||
int retval = 0;
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
interface = usb_find_interface(&lcd_driver, subminor);
|
||||
if (!interface) {
|
||||
err ("USBLCD: %s - error, can't find device for minor %d",
|
||||
__FUNCTION__, subminor);
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* increment our usage count for the device */
|
||||
kref_get(&dev->kref);
|
||||
|
||||
/* save our object in the file's private structure */
|
||||
file->private_data = dev;
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int lcd_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
|
||||
dev = (struct usb_lcd *)file->private_data;
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* decrement the count on our device */
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int retval = 0;
|
||||
int bytes_read;
|
||||
|
||||
dev = (struct usb_lcd *)file->private_data;
|
||||
|
||||
/* do a blocking bulk read to get data from the device */
|
||||
retval = usb_bulk_msg(dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
|
||||
dev->bulk_in_buffer,
|
||||
min(dev->bulk_in_size, count),
|
||||
&bytes_read, 10000);
|
||||
|
||||
/* if the read was successful, copy the data to userspace */
|
||||
if (!retval) {
|
||||
if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
|
||||
retval = -EFAULT;
|
||||
else
|
||||
retval = bytes_read;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
u16 bcdDevice;
|
||||
char buf[30];
|
||||
|
||||
dev = (struct usb_lcd *)file->private_data;
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_GET_HARD_VERSION:
|
||||
bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
|
||||
sprintf(buf,"%1d%1d.%1d%1d",
|
||||
(bcdDevice & 0xF000)>>12,
|
||||
(bcdDevice & 0xF00)>>8,
|
||||
(bcdDevice & 0xF0)>>4,
|
||||
(bcdDevice & 0xF));
|
||||
if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IOCTL_GET_DRV_VERSION:
|
||||
sprintf(buf,DRIVER_VERSION);
|
||||
if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lcd_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
|
||||
dev = (struct usb_lcd *)urb->context;
|
||||
|
||||
/* sync/async unlink faults aren't errors */
|
||||
if (urb->status &&
|
||||
!(urb->status == -ENOENT ||
|
||||
urb->status == -ECONNRESET ||
|
||||
urb->status == -ESHUTDOWN)) {
|
||||
dbg("USBLCD: %s - nonzero write bulk status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
}
|
||||
|
||||
/* free up our allocated buffer */
|
||||
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
}
|
||||
|
||||
static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int retval = 0;
|
||||
struct urb *urb = NULL;
|
||||
char *buf = NULL;
|
||||
|
||||
dev = (struct usb_lcd *)file->private_data;
|
||||
|
||||
/* verify that we actually have some data to write */
|
||||
if (count == 0)
|
||||
goto exit;
|
||||
|
||||
/* create a urb, and a buffer for it, and copy the data to the urb */
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
|
||||
if (!buf) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (copy_from_user(buf, user_buffer, count)) {
|
||||
retval = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* initialize the urb properly */
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
|
||||
buf, count, lcd_write_bulk_callback, dev);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
/* send the data out the bulk port */
|
||||
retval = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* release our reference to this urb, the USB core will eventually free it entirely */
|
||||
usb_free_urb(urb);
|
||||
|
||||
exit:
|
||||
return count;
|
||||
|
||||
error:
|
||||
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct file_operations lcd_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = lcd_read,
|
||||
.write = lcd_write,
|
||||
.open = lcd_open,
|
||||
.ioctl = lcd_ioctl,
|
||||
.release = lcd_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* * usb class driver info in order to get a minor number from the usb core,
|
||||
* * and to have the device registered with devfs and the driver core
|
||||
* */
|
||||
static struct usb_class_driver lcd_class = {
|
||||
.name = "usb/lcd%d",
|
||||
.fops = &lcd_fops,
|
||||
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
|
||||
.minor_base = USBLCD_MINOR,
|
||||
};
|
||||
|
||||
static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_lcd *dev = NULL;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
size_t buffer_size;
|
||||
int i;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
err("Out of memory");
|
||||
goto error;
|
||||
}
|
||||
memset(dev, 0x00, sizeof(*dev));
|
||||
kref_init(&dev->kref);
|
||||
|
||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->interface = interface;
|
||||
|
||||
if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
|
||||
warn(KERN_INFO "USBLCD model not supported.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* set up the endpoint information */
|
||||
/* use only the first bulk-in and bulk-out endpoints */
|
||||
iface_desc = interface->cur_altsetting;
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (!dev->bulk_in_endpointAddr &&
|
||||
(endpoint->bEndpointAddress & USB_DIR_IN) &&
|
||||
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_BULK)) {
|
||||
/* we found a bulk in endpoint */
|
||||
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
dev->bulk_in_size = buffer_size;
|
||||
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
if (!dev->bulk_in_buffer) {
|
||||
err("Could not allocate bulk_in_buffer");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev->bulk_out_endpointAddr &&
|
||||
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
|
||||
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_BULK)) {
|
||||
/* we found a bulk out endpoint */
|
||||
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
|
||||
}
|
||||
}
|
||||
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
|
||||
err("Could not find both bulk-in and bulk-out endpoints");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* save our data pointer in this interface device */
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
/* we can register the device now, as it is ready */
|
||||
retval = usb_register_dev(interface, &lcd_class);
|
||||
if (retval) {
|
||||
/* something prevented us from registering this driver */
|
||||
err("Not able to get a minor for this device.");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
i = le16_to_cpu(dev->udev->descriptor.bcdDevice);
|
||||
|
||||
info("USBLCD Version %1d%1d.%1d%1d found at address %d",
|
||||
(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
|
||||
dev->udev->devnum);
|
||||
|
||||
/* let the user know what node this device is now attached to */
|
||||
info("USB LCD device now attached to USBLCD-%d", interface->minor);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dev)
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void lcd_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int minor = interface->minor;
|
||||
|
||||
/* prevent skel_open() from racing skel_disconnect() */
|
||||
lock_kernel();
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &lcd_class);
|
||||
|
||||
unlock_kernel();
|
||||
|
||||
/* decrement our usage count */
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
|
||||
info("USB LCD #%d now disconnected", minor);
|
||||
}
|
||||
|
||||
static struct usb_driver lcd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usblcd",
|
||||
.probe = lcd_probe,
|
||||
.disconnect = lcd_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
static int __init usb_lcd_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = usb_register(&lcd_driver);
|
||||
if (result)
|
||||
err("usb_register failed. Error number %d", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void __exit usb_lcd_exit(void)
|
||||
{
|
||||
usb_deregister(&lcd_driver);
|
||||
}
|
||||
|
||||
module_init(usb_lcd_init);
|
||||
module_exit(usb_lcd_exit);
|
||||
|
||||
MODULE_AUTHOR("Georges Toth <g.toth@e-biz.lu>");
|
||||
MODULE_DESCRIPTION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
181
drivers/usb/misc/usbled.c
Normal file
181
drivers/usb/misc/usbled.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* USB LED driver - 1.1
|
||||
*
|
||||
* Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
||||
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
|
||||
#define DRIVER_DESC "USB LED Driver"
|
||||
|
||||
#define VENDOR_ID 0x0fc5
|
||||
#define PRODUCT_ID 0x1223
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
||||
struct usb_led {
|
||||
struct usb_device * udev;
|
||||
unsigned char blue;
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
};
|
||||
|
||||
#define BLUE 0x04
|
||||
#define RED 0x02
|
||||
#define GREEN 0x01
|
||||
static void change_color(struct usb_led *led)
|
||||
{
|
||||
int retval;
|
||||
unsigned char color = 0x07;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&led->udev->dev, "out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (led->blue)
|
||||
color &= ~(BLUE);
|
||||
if (led->red)
|
||||
color &= ~(RED);
|
||||
if (led->green)
|
||||
color &= ~(GREEN);
|
||||
dev_dbg(&led->udev->dev,
|
||||
"blue = %d, red = %d, green = %d, color = %.2x\n",
|
||||
led->blue, led->red, led->green, color);
|
||||
|
||||
retval = usb_control_msg(led->udev,
|
||||
usb_sndctrlpipe(led->udev, 0),
|
||||
0x12,
|
||||
0xc8,
|
||||
(0x02 * 0x100) + 0x0a,
|
||||
(0x00 * 0x100) + color,
|
||||
buffer,
|
||||
8,
|
||||
2000);
|
||||
if (retval)
|
||||
dev_dbg(&led->udev->dev, "retval = %d\n", retval);
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
#define show_set(value) \
|
||||
static ssize_t show_##value(struct device *dev, char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct usb_led *led = usb_get_intfdata(intf); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", led->value); \
|
||||
} \
|
||||
static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct usb_led *led = usb_get_intfdata(intf); \
|
||||
int temp = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
led->value = temp; \
|
||||
change_color(led); \
|
||||
return count; \
|
||||
} \
|
||||
static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
|
||||
show_set(blue);
|
||||
show_set(red);
|
||||
show_set(green);
|
||||
|
||||
static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_led *dev = NULL;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev_err(&interface->dev, "Out of memory\n");
|
||||
goto error;
|
||||
}
|
||||
memset (dev, 0x00, sizeof (*dev));
|
||||
|
||||
dev->udev = usb_get_dev(udev);
|
||||
|
||||
usb_set_intfdata (interface, dev);
|
||||
|
||||
device_create_file(&interface->dev, &dev_attr_blue);
|
||||
device_create_file(&interface->dev, &dev_attr_red);
|
||||
device_create_file(&interface->dev, &dev_attr_green);
|
||||
|
||||
dev_info(&interface->dev, "USB LED device now attached\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void led_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_led *dev;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
usb_set_intfdata (interface, NULL);
|
||||
|
||||
device_remove_file(&interface->dev, &dev_attr_blue);
|
||||
device_remove_file(&interface->dev, &dev_attr_red);
|
||||
device_remove_file(&interface->dev, &dev_attr_green);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
kfree(dev);
|
||||
|
||||
dev_info(&interface->dev, "USB LED now disconnected\n");
|
||||
}
|
||||
|
||||
static struct usb_driver led_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usbled",
|
||||
.probe = led_probe,
|
||||
.disconnect = led_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
static int __init usb_led_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
retval = usb_register(&led_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit usb_led_exit(void)
|
||||
{
|
||||
usb_deregister(&led_driver);
|
||||
}
|
||||
|
||||
module_init (usb_led_init);
|
||||
module_exit (usb_led_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
2140
drivers/usb/misc/usbtest.c
Normal file
2140
drivers/usb/misc/usbtest.c
Normal file
文件差異過大導致無法顯示
Load Diff
674
drivers/usb/misc/uss720.c
Normal file
674
drivers/usb/misc/uss720.c
Normal file
@@ -0,0 +1,674 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* uss720.c -- USS720 USB Parport Cable.
|
||||
*
|
||||
* Copyright (C) 1999
|
||||
* Thomas Sailer (sailer@ife.ee.ethz.ch)
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Based on parport_pc.c
|
||||
*
|
||||
* History:
|
||||
* 0.1 04.08.99 Created
|
||||
* 0.2 07.08.99 Some fixes mainly suggested by Tim Waugh
|
||||
* Interrupt handling currently disabled because
|
||||
* usb_request_irq crashes somewhere within ohci.c
|
||||
* for no apparent reason (that is for me, anyway)
|
||||
* ECP currently untested
|
||||
* 0.3 10.08.99 fixing merge errors
|
||||
* 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable
|
||||
* 0.5 20.09.99 usb_control_msg wrapper used
|
||||
* Nov01.00 usb_device_table support by Adam J. Richter
|
||||
* 08.04.01 Identify version on module load. gb
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/parport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.5"
|
||||
#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch"
|
||||
#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct parport_uss720_private {
|
||||
struct usb_device *usbdev;
|
||||
void *irqhandle;
|
||||
unsigned int irqpipe;
|
||||
unsigned char reg[7]; /* USB registers */
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
static const unsigned char regindex[9] = {
|
||||
4, 0, 1, 5, 5, 0, 2, 3, 6
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!usbdev)
|
||||
return -1;
|
||||
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000);
|
||||
if (ret != 7) {
|
||||
printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n",
|
||||
(unsigned int)reg, ret);
|
||||
ret = -1;
|
||||
} else {
|
||||
#if 0
|
||||
printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
(unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
|
||||
(unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
|
||||
(unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
|
||||
#endif
|
||||
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
|
||||
if (priv->reg[2] & priv->reg[1] & 0x10)
|
||||
parport_generic_irq(0, pp, NULL);
|
||||
ret = 0;
|
||||
}
|
||||
if (val)
|
||||
*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
int ret;
|
||||
|
||||
if (!usbdev)
|
||||
return -1;
|
||||
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000);
|
||||
if (ret) {
|
||||
printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n",
|
||||
(unsigned int)reg, (unsigned int)val, ret);
|
||||
} else {
|
||||
#if 0
|
||||
printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n",
|
||||
(unsigned int)reg, (unsigned int)val);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* ECR modes */
|
||||
#define ECR_SPP 00
|
||||
#define ECR_PS2 01
|
||||
#define ECR_PPF 02
|
||||
#define ECR_ECP 03
|
||||
#define ECR_EPP 04
|
||||
|
||||
/* Safely change the mode bits in the ECR */
|
||||
static int change_mode(struct parport *pp, int m)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
int mode;
|
||||
|
||||
if (get_1284_register(pp, 6, NULL))
|
||||
return -EIO;
|
||||
/* Bits <7:5> contain the mode. */
|
||||
mode = (priv->reg[2] >> 5) & 0x7;
|
||||
if (mode == m)
|
||||
return 0;
|
||||
/* We have to go through mode 000 or 001 */
|
||||
if (mode > ECR_PS2 && m > ECR_PS2)
|
||||
if (change_mode(pp, ECR_PS2))
|
||||
return -EIO;
|
||||
|
||||
if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
|
||||
/* This mode resets the FIFO, so we may
|
||||
* have to wait for it to drain first. */
|
||||
unsigned long expire = jiffies + pp->physport->cad->timeout;
|
||||
switch (mode) {
|
||||
case ECR_PPF: /* Parallel Port FIFO mode */
|
||||
case ECR_ECP: /* ECP Parallel Port mode */
|
||||
/* Poll slowly. */
|
||||
for (;;) {
|
||||
if (get_1284_register(pp, 6, NULL))
|
||||
return -EIO;
|
||||
if (priv->reg[2] & 0x01)
|
||||
break;
|
||||
if (time_after_eq (jiffies, expire))
|
||||
/* The FIFO is stuck. */
|
||||
return -EBUSY;
|
||||
msleep_interruptible(10);
|
||||
if (signal_pending (current))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Set the mode. */
|
||||
if (set_1284_register(pp, 6, m << 5))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear TIMEOUT BIT in EPP MODE
|
||||
*/
|
||||
static int clear_epp_timeout(struct parport *pp)
|
||||
{
|
||||
unsigned char stat;
|
||||
|
||||
if (get_1284_register(pp, 1, &stat))
|
||||
return 1;
|
||||
return stat & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Access functions.
|
||||
*/
|
||||
#if 0
|
||||
static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
|
||||
{
|
||||
struct parport *pp = (struct parport *)dev_id;
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
|
||||
if (usbstatus != 0 || len < 4 || !buffer)
|
||||
return 1;
|
||||
memcpy(priv->reg, buffer, 4);
|
||||
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
|
||||
if (priv->reg[2] & priv->reg[1] & 0x10)
|
||||
parport_generic_irq(0, pp, NULL);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parport_uss720_write_data(struct parport *pp, unsigned char d)
|
||||
{
|
||||
set_1284_register(pp, 0, d);
|
||||
}
|
||||
|
||||
static unsigned char parport_uss720_read_data(struct parport *pp)
|
||||
{
|
||||
unsigned char ret;
|
||||
|
||||
if (get_1284_register(pp, 0, &ret))
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void parport_uss720_write_control(struct parport *pp, unsigned char d)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
|
||||
d = (d & 0xf) | (priv->reg[1] & 0xf0);
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return;
|
||||
priv->reg[1] = d;
|
||||
}
|
||||
|
||||
static unsigned char parport_uss720_read_control(struct parport *pp)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
return priv->reg[1] & 0xf; /* Use soft copy */
|
||||
}
|
||||
|
||||
static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
unsigned char d;
|
||||
|
||||
mask &= 0x0f;
|
||||
val &= 0x0f;
|
||||
d = (priv->reg[1] & (~mask)) ^ val;
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return 0;
|
||||
priv->reg[1] = d;
|
||||
return d & 0xf;
|
||||
}
|
||||
|
||||
static unsigned char parport_uss720_read_status(struct parport *pp)
|
||||
{
|
||||
unsigned char ret;
|
||||
|
||||
if (get_1284_register(pp, 1, &ret))
|
||||
return 0;
|
||||
return ret & 0xf8;
|
||||
}
|
||||
|
||||
static void parport_uss720_disable_irq(struct parport *pp)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
unsigned char d;
|
||||
|
||||
d = priv->reg[1] & ~0x10;
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return;
|
||||
priv->reg[1] = d;
|
||||
}
|
||||
|
||||
static void parport_uss720_enable_irq(struct parport *pp)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
unsigned char d;
|
||||
|
||||
d = priv->reg[1] | 0x10;
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return;
|
||||
priv->reg[1] = d;
|
||||
}
|
||||
|
||||
static void parport_uss720_data_forward (struct parport *pp)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
unsigned char d;
|
||||
|
||||
d = priv->reg[1] & ~0x20;
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return;
|
||||
priv->reg[1] = d;
|
||||
}
|
||||
|
||||
static void parport_uss720_data_reverse (struct parport *pp)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
unsigned char d;
|
||||
|
||||
d = priv->reg[1] | 0x20;
|
||||
if (set_1284_register(pp, 2, d))
|
||||
return;
|
||||
priv->reg[1] = d;
|
||||
}
|
||||
|
||||
static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s)
|
||||
{
|
||||
s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
|
||||
s->u.pc.ecr = 0x24;
|
||||
}
|
||||
|
||||
static void parport_uss720_save_state(struct parport *pp, struct parport_state *s)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
|
||||
if (get_1284_register(pp, 2, NULL))
|
||||
return;
|
||||
s->u.pc.ctr = priv->reg[1];
|
||||
s->u.pc.ecr = priv->reg[2];
|
||||
}
|
||||
|
||||
static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
|
||||
{
|
||||
set_1284_register(pp, 2, s->u.pc.ctr);
|
||||
set_1284_register(pp, 6, s->u.pc.ecr);
|
||||
get_1284_register(pp, 2, NULL);
|
||||
}
|
||||
|
||||
static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
size_t got = 0;
|
||||
|
||||
if (change_mode(pp, ECR_EPP))
|
||||
return 0;
|
||||
for (; got < length; got++) {
|
||||
if (get_1284_register(pp, 4, (char *)buf))
|
||||
break;
|
||||
buf++;
|
||||
if (priv->reg[0] & 0x01) {
|
||||
clear_epp_timeout(pp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
change_mode(pp, ECR_PS2);
|
||||
return got;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
|
||||
{
|
||||
#if 0
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
size_t written = 0;
|
||||
|
||||
if (change_mode(pp, ECR_EPP))
|
||||
return 0;
|
||||
for (; written < length; written++) {
|
||||
if (set_1284_register(pp, 4, (char *)buf))
|
||||
break;
|
||||
((char*)buf)++;
|
||||
if (get_1284_register(pp, 1, NULL))
|
||||
break;
|
||||
if (priv->reg[0] & 0x01) {
|
||||
clear_epp_timeout(pp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
change_mode(pp, ECR_PS2);
|
||||
return written;
|
||||
#else
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
int rlen;
|
||||
int i;
|
||||
|
||||
if (!usbdev)
|
||||
return 0;
|
||||
if (change_mode(pp, ECR_EPP))
|
||||
return 0;
|
||||
i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000);
|
||||
if (i)
|
||||
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buf, length, rlen);
|
||||
change_mode(pp, ECR_PS2);
|
||||
return rlen;
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
size_t got = 0;
|
||||
|
||||
if (change_mode(pp, ECR_EPP))
|
||||
return 0;
|
||||
for (; got < length; got++) {
|
||||
if (get_1284_register(pp, 3, (char *)buf))
|
||||
break;
|
||||
buf++;
|
||||
if (priv->reg[0] & 0x01) {
|
||||
clear_epp_timeout(pp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
change_mode(pp, ECR_PS2);
|
||||
return got;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
size_t written = 0;
|
||||
|
||||
if (change_mode(pp, ECR_EPP))
|
||||
return 0;
|
||||
for (; written < length; written++) {
|
||||
if (set_1284_register(pp, 3, *(char *)buf))
|
||||
break;
|
||||
buf++;
|
||||
if (get_1284_register(pp, 1, NULL))
|
||||
break;
|
||||
if (priv->reg[0] & 0x01) {
|
||||
clear_epp_timeout(pp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
change_mode(pp, ECR_PS2);
|
||||
return written;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
int rlen;
|
||||
int i;
|
||||
|
||||
if (!usbdev)
|
||||
return 0;
|
||||
if (change_mode(pp, ECR_ECP))
|
||||
return 0;
|
||||
i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
|
||||
if (i)
|
||||
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
|
||||
change_mode(pp, ECR_PS2);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
int rlen;
|
||||
int i;
|
||||
|
||||
if (!usbdev)
|
||||
return 0;
|
||||
if (change_mode(pp, ECR_ECP))
|
||||
return 0;
|
||||
i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000);
|
||||
if (i)
|
||||
printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen);
|
||||
change_mode(pp, ECR_PS2);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
|
||||
{
|
||||
size_t written = 0;
|
||||
|
||||
if (change_mode(pp, ECR_ECP))
|
||||
return 0;
|
||||
for (; written < len; written++) {
|
||||
if (set_1284_register(pp, 5, *(char *)buffer))
|
||||
break;
|
||||
buffer++;
|
||||
}
|
||||
change_mode(pp, ECR_PS2);
|
||||
return written;
|
||||
}
|
||||
|
||||
static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
|
||||
{
|
||||
struct parport_uss720_private *priv = pp->private_data;
|
||||
struct usb_device *usbdev = priv->usbdev;
|
||||
int rlen;
|
||||
int i;
|
||||
|
||||
if (!usbdev)
|
||||
return 0;
|
||||
if (change_mode(pp, ECR_PPF))
|
||||
return 0;
|
||||
i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
|
||||
if (i)
|
||||
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
|
||||
change_mode(pp, ECR_PS2);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct parport_operations parport_uss720_ops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.write_data = parport_uss720_write_data,
|
||||
.read_data = parport_uss720_read_data,
|
||||
|
||||
.write_control = parport_uss720_write_control,
|
||||
.read_control = parport_uss720_read_control,
|
||||
.frob_control = parport_uss720_frob_control,
|
||||
|
||||
.read_status = parport_uss720_read_status,
|
||||
|
||||
.enable_irq = parport_uss720_enable_irq,
|
||||
.disable_irq = parport_uss720_disable_irq,
|
||||
|
||||
.data_forward = parport_uss720_data_forward,
|
||||
.data_reverse = parport_uss720_data_reverse,
|
||||
|
||||
.init_state = parport_uss720_init_state,
|
||||
.save_state = parport_uss720_save_state,
|
||||
.restore_state = parport_uss720_restore_state,
|
||||
|
||||
.epp_write_data = parport_uss720_epp_write_data,
|
||||
.epp_read_data = parport_uss720_epp_read_data,
|
||||
.epp_write_addr = parport_uss720_epp_write_addr,
|
||||
.epp_read_addr = parport_uss720_epp_read_addr,
|
||||
|
||||
.ecp_write_data = parport_uss720_ecp_write_data,
|
||||
.ecp_read_data = parport_uss720_ecp_read_data,
|
||||
.ecp_write_addr = parport_uss720_ecp_write_addr,
|
||||
|
||||
.compat_write_data = parport_uss720_write_compat,
|
||||
.nibble_read_data = parport_ieee1284_read_nibble,
|
||||
.byte_read_data = parport_ieee1284_read_byte,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int uss720_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *usbdev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface;
|
||||
struct usb_host_endpoint *endpoint;
|
||||
struct parport_uss720_private *priv;
|
||||
struct parport *pp;
|
||||
int i;
|
||||
|
||||
printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
|
||||
le16_to_cpu(usbdev->descriptor.idVendor),
|
||||
le16_to_cpu(usbdev->descriptor.idProduct));
|
||||
|
||||
/* our known interfaces have 3 alternate settings */
|
||||
if (intf->num_altsetting != 3)
|
||||
return -ENODEV;
|
||||
|
||||
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
|
||||
printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
|
||||
/*
|
||||
* Allocate parport interface
|
||||
*/
|
||||
printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
|
||||
|
||||
if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
|
||||
printk(KERN_WARNING "usb-uss720: could not register parport\n");
|
||||
goto probe_abort;
|
||||
}
|
||||
|
||||
pp->private_data = priv;
|
||||
priv->usbdev = usbdev;
|
||||
pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
|
||||
|
||||
/* set the USS720 control register to manual mode, no ECP compression, enable all ints */
|
||||
set_1284_register(pp, 7, 0x00);
|
||||
set_1284_register(pp, 6, 0x30); /* PS/2 mode */
|
||||
set_1284_register(pp, 2, 0x0c);
|
||||
/* debugging */
|
||||
get_1284_register(pp, 0, NULL);
|
||||
printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
|
||||
|
||||
endpoint = &interface->endpoint[2];
|
||||
printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
|
||||
#if 0
|
||||
priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
|
||||
i = usb_request_irq(usbdev, priv->irqpipe,
|
||||
uss720_irq, endpoint->bInterval,
|
||||
pp, &priv->irqhandle);
|
||||
if (i) {
|
||||
printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
|
||||
goto probe_abort_port;
|
||||
}
|
||||
#endif
|
||||
parport_announce_port(pp);
|
||||
|
||||
usb_set_intfdata (intf, pp);
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
probe_abort_port:
|
||||
parport_put_port(pp);
|
||||
#endif
|
||||
probe_abort:
|
||||
kfree(priv);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void uss720_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct parport *pp = usb_get_intfdata (intf);
|
||||
struct parport_uss720_private *priv;
|
||||
|
||||
usb_set_intfdata (intf, NULL);
|
||||
if (pp) {
|
||||
priv = pp->private_data;
|
||||
parport_remove_port(pp);
|
||||
#if 0
|
||||
usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
|
||||
#endif
|
||||
priv->usbdev = NULL;
|
||||
parport_put_port(pp);
|
||||
kfree(priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* table of cables that work through this driver */
|
||||
static struct usb_device_id uss720_table [] = {
|
||||
{ USB_DEVICE(0x047e, 0x1001) },
|
||||
{ USB_DEVICE(0x0557, 0x2001) },
|
||||
{ USB_DEVICE(0x0729, 0x1284) },
|
||||
{ USB_DEVICE(0x1293, 0x0002) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, uss720_table);
|
||||
|
||||
|
||||
static struct usb_driver uss720_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "uss720",
|
||||
.probe = uss720_probe,
|
||||
.disconnect = uss720_disconnect,
|
||||
.id_table = uss720_table,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
MODULE_AUTHOR( DRIVER_AUTHOR );
|
||||
MODULE_DESCRIPTION( DRIVER_DESC );
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int __init uss720_init(void)
|
||||
{
|
||||
int retval;
|
||||
retval = usb_register(&uss720_driver);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
info(DRIVER_VERSION ":" DRIVER_DESC);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit uss720_cleanup(void)
|
||||
{
|
||||
usb_deregister(&uss720_driver);
|
||||
}
|
||||
|
||||
module_init(uss720_init);
|
||||
module_exit(uss720_cleanup);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
Reference in New Issue
Block a user