Rework of the usb_serial driver:

* Refactored everything to C++ with the different devices as subclasses
* Added proper ACM detection with parsing of the ACM descriptors
* Added device transfer error handling and fixed some concurency issues
* Big cleanup to conform to our style guide

This should make at least ACM stable to use. Commiting this over my K850i with
ACM compliant USB modem and UMTS data connection. Note that support for all
other device classes (Prolific, FTDI and KLSI) is untested but should work the
same as before. Note also that since we currently lack a TTY module this will
only build/work for R5 or Dano with the proper TTY headers.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23634 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-01-19 15:24:23 +00:00
parent a39fca4de3
commit 7aa661d403
32 changed files with 2704 additions and 2168 deletions

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "ACM.h"
#include "Driver.h"
ACMDevice::ACMDevice(usb_device device, uint16 vendorID, uint16 productID,
const char *description)
: SerialDevice(device, vendorID, productID, description)
{
}
status_t
ACMDevice::AddDevice(const usb_configuration_info *config)
{
TRACE_FUNCALLS("> ACMDevice::AddDevice(0x%08x, 0x%08x)\n", this, config);
status_t status = ENODEV;
uint8 masterIndex = 0;
uint8 slaveIndex = 0;
for (size_t i = 0; i < config->interface_count && status < B_OK; i++) {
usb_interface_info *interface = config->interface[i].active;
usb_interface_descriptor *descriptor = interface->descr;
if (descriptor->interface_class == USB_INT_CLASS_CDC
&& descriptor->interface_subclass == USB_INT_SUBCLASS_ACM
&& interface->generic_count > 0) {
// try to find and interpret the union functional descriptor
for (size_t j = 0; j < interface->generic_count; j++) {
usb_generic_descriptor *generic = &interface->generic[j]->generic;
if (generic->length >= 5
&& generic->data[0] == FUNCTIONAL_SUBTYPE_UNION) {
masterIndex = generic->data[1];
slaveIndex = generic->data[2];
status = B_OK;
break;
}
}
}
}
if (status == B_OK && masterIndex < config->interface_count) {
// check that the indicated master interface fits our need
usb_interface_info *interface = config->interface[masterIndex].active;
usb_interface_descriptor *descriptor = interface->descr;
if ((descriptor->interface_class == USB_INT_CLASS_CDC
|| descriptor->interface_class == USB_INT_CLASS_CDC_DATA)
&& interface->endpoint_count >= 1) {
SetControlPipe(interface->endpoint[0].handle);
} else
status = ENODEV;
}
if (status == B_OK && slaveIndex < config->interface_count) {
// check that the indicated slave interface fits our need
usb_interface_info *interface = config->interface[slaveIndex].active;
usb_interface_descriptor *descriptor = interface->descr;
if (descriptor->interface_class == USB_INT_CLASS_CDC_DATA
&& interface->endpoint_count >= 2) {
if (!(interface->endpoint[0].descr->endpoint_address & USB_EP_ADDR_DIR_IN))
SetWritePipe(interface->endpoint[0].handle);
else
SetReadPipe(interface->endpoint[0].handle);
if (interface->endpoint[1].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
SetReadPipe(interface->endpoint[1].handle);
else
SetWritePipe(interface->endpoint[1].handle);
} else
status = ENODEV;
}
TRACE_FUNCRET("< ACMDevice::AddDevice() returns: 0x%08x\n", status);
return status;
}
status_t
ACMDevice::SetLineCoding(usb_serial_line_coding *lineCoding)
{
TRACE_FUNCALLS("> ACMDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n",
this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity,
lineCoding->databits);
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
SET_LINE_CODING, 0, 0,
sizeof(usb_serial_line_coding),
lineCoding, &length);
TRACE_FUNCRET("< ACMDevice::SetLineCoding() returns: 0x%08x\n", status);
return status;
}
status_t
ACMDevice::SetControlLineState(uint16 state)
{
TRACE_FUNCALLS("> ACMDevice::SetControlLineState(0x%08x, 0x%04x)\n", this, state);
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
SET_CONTROL_LINE_STATE, state, 0, 0, NULL, &length);
TRACE_FUNCRET("< ACMDevice::SetControlLineState() returns: 0x%08x\n", status);
return status;
}
void
ACMDevice::OnWrite(const char *buffer, size_t *numBytes)
{
memcpy(WriteBuffer(), buffer, *numBytes);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_ACM_H_
#define _USB_ACM_H_
#include "SerialDevice.h"
/* requests for CDC ACM devices */
#define SEND_ENCAPSULATED_COMMAND 0x00
#define GET_ENCAPSULATED_RESPONSE 0x01
#define SET_LINE_CODING 0x20
#define SET_CONTROL_LINE_STATE 0x22
/* notifications for CDC ACM devices */
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
class ACMDevice : public SerialDevice {
public:
ACMDevice(usb_device device, uint16 vendorID,
uint16 productID, const char *description);
virtual status_t AddDevice(const usb_configuration_info *config);
virtual status_t SetLineCoding(usb_serial_line_coding *coding);
virtual status_t SetControlLineState(uint16 state);
virtual void OnWrite(const char *buffer, size_t *numBytes);
};
#endif //_USB_ACM_H_

View File

@ -0,0 +1,54 @@
#ifndef _BEOS_COMPATIBILITY_H_
#define _BEOS_COMPATIBILITY_H_
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
typedef struct benaphore {
sem_id sem;
int32 count;
} benaphore;
static inline status_t
benaphore_init(benaphore *ben, const char *name)
{
if (ben == NULL || name == NULL)
return B_BAD_VALUE;
ben->count = 1;
ben->sem = create_sem(0, name);
if (ben->sem >= B_OK)
return B_OK;
return ben->sem;
}
static inline void
benaphore_destroy(benaphore *ben)
{
delete_sem(ben->sem);
ben->sem = -1;
}
static inline status_t
benaphore_lock(benaphore *ben)
{
if (atomic_add(&ben->count, -1) <= 0)
return acquire_sem(ben->sem);
return B_OK;
}
static inline status_t
benaphore_unlock(benaphore *ben)
{
if (atomic_add(&ben->count, 1) < 0)
return release_sem(ben->sem);
return B_OK;
}
#endif // HAIKU_TARGET_PLATFORM_HAIKU
#endif // _BEOS_COMPATIBILITY_H_

View File

@ -0,0 +1,347 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include "Driver.h"
#include "SerialDevice.h"
#include "USB3.h"
static const char *sDeviceBaseName = "ports/usb";
SerialDevice *gSerialDevices[DEVICES_COUNT];
char *gDeviceNames[DEVICES_COUNT + 1];
usb_module_info *gUSBModule = NULL;
tty_module_info *gTTYModule = NULL;
struct ddomain gSerialDomain;
sem_id gDriverLock = -1;
status_t
usb_serial_device_added(usb_device device, void **cookie)
{
TRACE_FUNCALLS("> usb_serial_device_added(0x%08x, 0x%08x)\n", device, cookie);
status_t status = B_OK;
const usb_device_descriptor *descriptor
= gUSBModule->get_device_descriptor(device);
TRACE_ALWAYS("probing device: 0x%04x/0x%04x\n", descriptor->vendor_id,
descriptor->product_id);
*cookie = NULL;
SerialDevice *serialDevice = SerialDevice::MakeDevice(device,
descriptor->vendor_id, descriptor->product_id);
const usb_configuration_info *configuration
= gUSBModule->get_nth_configuration(device, 0);
if (!configuration)
return B_ERROR;
status = serialDevice->AddDevice(configuration);
if (status < B_OK) {
delete serialDevice;
return status;
}
acquire_sem(gDriverLock);
for (int32 i = 0; i < DEVICES_COUNT; i++) {
if (gSerialDevices[i] != NULL)
continue;
status = serialDevice->Init();
if (status < B_OK) {
delete serialDevice;
return status;
}
gSerialDevices[i] = serialDevice;
*cookie = serialDevice;
release_sem(gDriverLock);
TRACE_ALWAYS("%s (0x%04x/0x%04x) added\n", serialDevice->Description(),
descriptor->vendor_id, descriptor->product_id);
return B_OK;
}
release_sem(gDriverLock);
return B_ERROR;
}
status_t
usb_serial_device_removed(void *cookie)
{
TRACE_FUNCALLS("> usb_serial_device_removed(0x%08x)\n", cookie);
acquire_sem(gDriverLock);
SerialDevice *device = (SerialDevice *)cookie;
for (int32 i = 0; i < DEVICES_COUNT; i++) {
if (gSerialDevices[i] == device) {
delete device;
gSerialDevices[i] = NULL;
break;
}
}
release_sem(gDriverLock);
TRACE_FUNCRET("< usb_serial_device_removed() returns\n");
return B_OK;
}
//#pragma mark -
/* init_hardware - called once the first time the driver is loaded */
status_t
init_hardware()
{
TRACE("init_hardware\n");
return B_OK;
}
/* init_driver - called every time the driver is loaded. */
status_t
init_driver()
{
load_settings();
create_log_file();
TRACE_FUNCALLS("> init_driver()\n");
status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule);
if (status < B_OK)
return status;
status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
if (status < B_OK) {
put_module(B_TTY_MODULE_NAME);
return status;
}
for (int32 i = 0; i < DEVICES_COUNT; i++)
gSerialDevices[i] = 0;
gDeviceNames[0] = NULL;
//load_driver_symbols(DRIVER_NAME);
gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock");
if (gDriverLock < B_OK) {
put_module(B_USB_MODULE_NAME);
put_module(B_TTY_MODULE_NAME);
return gDriverLock;
}
static usb_notify_hooks notifyHooks = {
&usb_serial_device_added,
&usb_serial_device_removed
};
gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
TRACE_FUNCRET("< init_driver() returns\n");
return B_OK;
}
/* uninit_driver - called every time the driver is unloaded */
void
uninit_driver()
{
TRACE_FUNCALLS("> uninit_driver()\n");
gUSBModule->uninstall_notify(DRIVER_NAME);
acquire_sem(gDriverLock);
for (int32 i = 0; i < DEVICES_COUNT; i++) {
if (gSerialDevices[i]) {
delete gSerialDevices[i];
gSerialDevices[i] = NULL;
}
}
for (int32 i = 0; gDeviceNames[i]; i++)
free(gDeviceNames[i]);
delete_sem(gDriverLock);
put_module(B_USB_MODULE_NAME);
put_module(B_TTY_MODULE_NAME);
TRACE_FUNCRET("< uninit_driver() returns\n");
}
bool
usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags)
{
TRACE_FUNCALLS("> usb_serial_service(0x%08x, 0x%08x, 0x%08x)\n", ptty, ddr, flags);
for (int32 i = 0; i < DEVICES_COUNT; i++) {
if (gSerialDevices[i] && gSerialDevices[i]->Service(ptty, ddr, flags)) {
TRACE_FUNCRET("< usb_serial_service() returns: true\n");
return true;
}
}
TRACE_FUNCRET("< usb_serial_service() returns: false\n");
return false;
}
/* usb_serial_open - handle open() calls */
static status_t
usb_serial_open(const char *name, uint32 flags, void **cookie)
{
TRACE_FUNCALLS("> usb_serial_open(%s, 0x%08x, 0x%08x)\n", name, flags, cookie);
acquire_sem(gDriverLock);
status_t status = ENODEV;
*cookie = NULL;
int i = strtol(name + strlen(sDeviceBaseName), NULL, 10);
if (i >= 0 && i < DEVICES_COUNT && gSerialDevices[i]) {
status = gSerialDevices[i]->Open(flags);
*cookie = gSerialDevices[i];
}
release_sem(gDriverLock);
TRACE_FUNCRET("< usb_serial_open() returns: 0x%08x\n", status);
return status;
}
/* usb_serial_read - handle read() calls */
static status_t
usb_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
{
TRACE_FUNCALLS("> usb_serial_read(0x%08x, %Ld, 0x%08x, %d)\n", cookie,
position, buffer, *numBytes);
SerialDevice *device = (SerialDevice *)cookie;
return device->Read((char *)buffer, numBytes);
}
/* usb_serial_write - handle write() calls */
static status_t
usb_serial_write(void *cookie, off_t position, const void *buffer,
size_t *numBytes)
{
TRACE_FUNCALLS("> usb_serial_write(0x%08x, %Ld, 0x%08x, %d)\n", cookie,
position, buffer, *numBytes);
SerialDevice *device = (SerialDevice *)cookie;
return device->Write((const char *)buffer, numBytes);
}
/* usb_serial_control - handle ioctl calls */
static status_t
usb_serial_control(void *cookie, uint32 op, void *arg, size_t length)
{
TRACE_FUNCALLS("> usb_serial_control(0x%08x, 0x%08x, 0x%08x, %d)\n",
cookie, op, arg, length);
SerialDevice *device = (SerialDevice *)cookie;
return device->Control(op, arg, length);
}
#if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
/* usb_serial_select - handle select start */
static status_t
usb_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
{
TRACE_FUNCALLS("> usb_serial_select(0x%08x, 0x%08x, 0x%08x, %p)\n",
cookie, event, ref, sync);
SerialDevice *device = (SerialDevice *)cookie;
return device->Select(event, ref, sync);
}
/* usb_serial_deselect - handle select exit */
static status_t
usb_serial_deselect(void *cookie, uint8 event, selectsync *sync)
{
TRACE_FUNCALLS("> usb_serial_deselect(0x%08x, 0x%08x, %p)\n",
cookie, event, sync);
SerialDevice *device = (SerialDevice *)cookie;
return device->DeSelect(event, sync);
}
#endif // DANO, HAIKU
/* usb_serial_close - handle close() calls */
static status_t
usb_serial_close(void *cookie)
{
TRACE_FUNCALLS("> usb_serial_close(0x%08x)\n", cookie);
SerialDevice *device = (SerialDevice *)cookie;
return device->Close();
}
/* usb_serial_free - called after last device is closed, and all i/o complete. */
static status_t
usb_serial_free(void *cookie)
{
TRACE_FUNCALLS("> usb_serial_free(0x%08x)\n", cookie);
SerialDevice *device = (SerialDevice *)cookie;
return device->Free();
}
/* publish_devices - null-terminated array of devices supported by this driver. */
const char **
publish_devices()
{
TRACE_FUNCALLS("> publish_devices()\n");
for (int32 i = 0; gDeviceNames[i]; i++)
free(gDeviceNames[i]);
int32 j = 0;
acquire_sem(gDriverLock);
for(int32 i = 0; i < DEVICES_COUNT; i++) {
if (gSerialDevices[i]) {
gDeviceNames[j] = (char *)malloc(strlen(sDeviceBaseName + 4));
if (gDeviceNames[j]) {
sprintf(gDeviceNames[j], "%s%ld", sDeviceBaseName, i);
j++;
} else
TRACE_ALWAYS("publish_devices - no memory to allocate device names\n");
}
}
gDeviceNames[j] = NULL;
release_sem(gDriverLock);
return (const char **)&gDeviceNames[0];
}
/* find_device - return poiter to device hooks structure for a given device */
device_hooks *
find_device(const char *name)
{
static device_hooks deviceHooks = {
usb_serial_open, /* -> open entry point */
usb_serial_close, /* -> close entry point */
usb_serial_free, /* -> free cookie */
usb_serial_control, /* -> control entry point */
usb_serial_read, /* -> read entry point */
usb_serial_write, /* -> write entry point */
#if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
usb_serial_select, /* -> select entry point */
usb_serial_deselect /* -> deselect entry point */
#endif
};
TRACE_FUNCALLS("> find_device(%s)\n", name);
return &deviceHooks;
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_SERIAL_DRIVER_H_
#define _USB_SERIAL_DRIVER_H_
#include <OS.h>
#include <KernelExport.h>
#include <Drivers.h>
#include "BeOSCompatibility.h"
#include "kernel_cpp.h"
#include "Tracing.h"
#include "USB3.h"
extern "C" {
#include <ttylayer.h>
}
#define DRIVER_NAME "usb_serial" // driver name for debug output
#define DEVICES_COUNT 20 // max simultaneously open devices
/* Some usefull helper defines ... */
#define SIZEOF(array) (sizeof(array) / sizeof(array[0])) /* size of array */
/* This one rounds the size to integral count of segs (segments) */
#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1))
/* Default device buffer size */
#define DEF_BUFFER_SIZE 0x200
/* line coding defines ... Come from CDC USB specs? */
#define LC_STOP_BIT_1 0
#define LC_STOP_BIT_2 2
#define LC_PARITY_NONE 0
#define LC_PARITY_ODD 1
#define LC_PARITY_EVEN 2
/* struct that represents line coding */
typedef struct usb_serial_line_coding_s {
uint32 speed;
uint8 stopbits;
uint8 parity;
uint8 databits;
} usb_serial_line_coding;
/* control line states */
#define CLS_LINE_DTR 0x0001
#define CLS_LINE_RTS 0x0002
/* attributes etc ...*/
#ifndef USB_EP_ADDR_DIR_IN
#define USB_EP_ADDR_DIR_IN 0x80
#define USB_EP_ADDR_DIR_OUT 0x00
#endif
#ifndef USB_EP_ATTR_CONTROL
#define USB_EP_ATTR_CONTROL 0x00
#define USB_EP_ATTR_ISOCHRONOUS 0x01
#define USB_EP_ATTR_BULK 0x02
#define USB_EP_ATTR_INTERRUPT 0x03
#endif
/* USB class - communication devices */
#define USB_DEV_CLASS_COMM 0x02
#define USB_INT_CLASS_CDC 0x02
#define USB_INT_SUBCLASS_ACM 0x02
#define USB_INT_CLASS_CDC_DATA 0x0a
#define USB_INT_SUBCLASS_DATA 0x00
// communication device subtypes
#define FUNCTIONAL_SUBTYPE_UNION 0x06
extern usb_module_info *gUSBModule;
extern tty_module_info *gTTYModule;
extern struct ddomain gSerialDomain;
extern "C" {
status_t usb_serial_device_added(usb_device device, void **cookie);
status_t usb_serial_device_removed(void *cookie);
status_t init_hardware();
void uninit_driver();
bool usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags);
status_t usb_serial_open(const char *name, uint32 flags, void **cookie);
status_t usb_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes);
status_t usb_serial_write(void *cookie, off_t position, const void *buffer, size_t *numBytes);
status_t usb_serial_control(void *cookie, uint32 op, void *arg, size_t length);
status_t usb_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync);
status_t usb_serial_deselect(void *coookie, uint8 event, selectsync *sync);
status_t usb_serial_close(void *cookie);
status_t usb_serial_free(void *cookie);
const char **publish_devices();
device_hooks *find_device(const char *name);
}
#endif //_USB_SERIAL_DRIVER_H_

View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "FTDI.h"
#include "FTDIRegs.h"
FTDIDevice::FTDIDevice(usb_device device, uint16 vendorID, uint16 productID,
const char *description)
: SerialDevice(device, vendorID, productID, description),
fHeaderLength(0),
fStatusMSR(0),
fStatusLSR(0)
{
}
status_t
FTDIDevice::AddDevice(const usb_configuration_info *config)
{
TRACE_FUNCALLS("> FTDIDevice::AddDevice(%08x, %08x)\n", this, config);
status_t status = ENODEV;
if (config->interface_count > 0) {
int32 pipesSet = 0;
usb_interface_info *interface = config->interface[0].active;
for (size_t i = 0; i < interface->endpoint_count; i++) {
usb_endpoint_info *endpoint = &interface->endpoint[i];
if (endpoint->descr->attributes == USB_EP_ATTR_BULK) {
if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
SetReadPipe(endpoint->handle);
if (++pipesSet >= 3)
break;
} else {
if (endpoint->descr->endpoint_address) {
SetControlPipe(endpoint->handle);
SetWritePipe(endpoint->handle);
pipesSet += 2;
if (pipesSet >= 3)
break;
}
}
}
}
if (pipesSet >= 3) {
if (ProductID() == PRODUCT_FTDI_8U100AX)
fHeaderLength = 1;
else
fHeaderLength = 0;
status = B_OK;
}
}
TRACE_FUNCRET("< FTDIDevice::AddDevice() returns: 0x%08x\n", status);
return status;
}
status_t
FTDIDevice::ResetDevice()
{
TRACE_FUNCALLS("> FTDIDevice::ResetDevice(0x%08x)\n", this);
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_RESET, FTDI_SIO_RESET_SIO,
FTDI_PIT_DEFAULT, 0, NULL, &length);
TRACE_FUNCRET("< FTDIDevice::ResetDevice() returns:%08x\n", status);
return status;
}
status_t
FTDIDevice::SetLineCoding(usb_serial_line_coding *lineCoding)
{
TRACE_FUNCALLS("> FTDIDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n",
this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity,
lineCoding->databits);
int32 rate = 0;
if (ProductID() == PRODUCT_FTDI_8U100AX) {
switch (lineCoding->speed) {
case 300: rate = ftdi_sio_b300; break;
case 600: rate = ftdi_sio_b600; break;
case 1200: rate = ftdi_sio_b1200; break;
case 2400: rate = ftdi_sio_b2400; break;
case 4800: rate = ftdi_sio_b4800; break;
case 9600: rate = ftdi_sio_b9600; break;
case 19200: rate = ftdi_sio_b19200; break;
case 38400: rate = ftdi_sio_b38400; break;
case 57600: rate = ftdi_sio_b57600; break;
case 115200: rate = ftdi_sio_b115200; break;
default:
rate = ftdi_sio_b19200;
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
"not supported by this hardware. Defaulted to %d\n",
lineCoding->speed, rate);
break;
}
} else {
switch (lineCoding->speed) {
case 300: rate = ftdi_8u232am_b300; break;
case 600: rate = ftdi_8u232am_b600; break;
case 1200: rate = ftdi_8u232am_b1200; break;
case 2400: rate = ftdi_8u232am_b2400; break;
case 4800: rate = ftdi_8u232am_b4800; break;
case 9600: rate = ftdi_8u232am_b9600; break;
case 19200: rate = ftdi_8u232am_b19200; break;
case 38400: rate = ftdi_8u232am_b38400; break;
case 57600: rate = ftdi_8u232am_b57600; break;
case 115200: rate = ftdi_8u232am_b115200; break;
case 230400: rate = ftdi_8u232am_b230400; break;
case 460800: rate = ftdi_8u232am_b460800; break;
case 921600: rate = ftdi_8u232am_b921600; break;
default:
rate = ftdi_sio_b19200;
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
"not supported by this hardware. Defaulted to %d\n",
lineCoding->speed, rate);
break;
}
}
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_SET_BAUD_RATE, rate,
FTDI_PIT_DEFAULT, 0, NULL, &length);
if (status != B_OK)
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status);
int32 data = 0;
switch (lineCoding->stopbits) {
case LC_STOP_BIT_2: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break;
case LC_STOP_BIT_1: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break;
default:
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong stopbits param: %d\n",
lineCoding->stopbits);
break;
}
switch (lineCoding->parity) {
case LC_PARITY_NONE: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break;
case LC_PARITY_EVEN: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break;
case LC_PARITY_ODD: data |= FTDI_SIO_SET_DATA_PARITY_ODD; break;
default:
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong parity param: %d\n",
lineCoding->parity);
break;
}
switch (lineCoding->databits) {
case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break;
case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break;
default:
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Wrong databits param: %d\n",
lineCoding->databits);
break;
}
length = 0;
status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_SET_DATA, data,
FTDI_PIT_DEFAULT, 0, NULL, &length);
if (status != B_OK)
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): data set request failed: %08x\n", status);
TRACE_FUNCRET("< FTDIDevice::SetLineCoding() returns: 0x%08x\n", status);
return status;
}
status_t
FTDIDevice::SetControlLineState(uint16 state)
{
TRACE_FUNCALLS("> FTDIDevice::SetControlLineState(0x%08x, 0x%04x)\n", this, state);
int32 control;
control = (state & CLS_LINE_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
control |= (state & CLS_LINE_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_MODEM_CTRL, control,
FTDI_PIT_DEFAULT, 0, NULL, &length);
if (status != B_OK)
TRACE_ALWAYS("= FTDIDevice::SetControlLineState(): control set request failed: 0x%08x\n", status);
TRACE_FUNCRET("< FTDIDevice::SetControlLineState() returns: 0x%08x\n", status);
return status;
}
void
FTDIDevice::OnRead(char **buffer, size_t *numBytes)
{
fStatusMSR = FTDI_GET_MSR(*buffer);
fStatusLSR = FTDI_GET_LSR(*buffer);
TRACE("FTDIDevice::OnRead(): MSR: 0x%02x LSR: 0x%02x\n", fStatusMSR, fStatusLSR);
*buffer += 2;
*numBytes -= 2;
}
void
FTDIDevice::OnWrite(const char *buffer, size_t *numBytes)
{
char *writeBuffer = WriteBuffer();
if (fHeaderLength > 0) {
if (*numBytes >= WriteBufferSize() - fHeaderLength)
*numBytes = WriteBufferSize() - fHeaderLength;
*writeBuffer = FTDI_OUT_TAG(*numBytes, FTDI_PIT_DEFAULT);
}
memcpy(writeBuffer + fHeaderLength, buffer, *numBytes);
*numBytes += fHeaderLength;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_FTDI_H_
#define _USB_FTDI_H_
#include "SerialDevice.h"
/* supported vendor and product ids */
#define VENDOR_FTDI 0x0403
#define PRODUCT_FTDI_8U100AX 0x8372
#define PRODUCT_FTDI_8U232AM 0x6001
#define FTDI_BUFFER_SIZE 64
class FTDIDevice : public SerialDevice {
public:
FTDIDevice(usb_device device, uint16 vendorID,
uint16 productID, const char *description);
virtual status_t AddDevice(const usb_configuration_info *config);
virtual status_t ResetDevice();
virtual status_t SetLineCoding(usb_serial_line_coding *coding);
virtual status_t SetControlLineState(uint16 state);
virtual void OnRead(char **buffer, size_t *numBytes);
virtual void OnWrite(const char *buffer, size_t *numBytes);
private:
size_t fHeaderLength;
uint8 fStatusMSR;
uint8 fStatusLSR;
};
#endif //_USB_FTDI_H_

View File

@ -19,7 +19,7 @@
/*
* Added to BeOS USB Serial Driver project by Siarzhuk Zharski
*
*
* $Source: /cvsroot/sis4be/usb_serial/uftdireg.h,v $
* $Author: zharik $
* $Revision: 1.1 $
@ -28,17 +28,17 @@
*/
/* Vendor Request Interface */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_STATUS 5 /* Retrieve current value of status reg */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_STATUS 5 /* Retrieve current value of status reg */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
/* Port Identifier Table */
#define FTDI_PIT_DEFAULT 0 /* SIOA */
#define FTDI_PIT_DEFAULT 0 /* SIOA */
#define FTDI_PIT_SIOA 1 /* SIOA */
#define FTDI_PIT_SIOB 2 /* SIOB */
#define FTDI_PIT_PARALLEL 3 /* Parallel */
@ -74,9 +74,9 @@ enum uftdi_type {
*
*/
/* FTDI_SIO_RESET */
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
/*
@ -142,16 +142,16 @@ enum {
*
*/
/* FTDI_SIO_SET_DATA */
#define FTDI_SIO_SET_DATA_BITS(n) (n)
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
#define FTDI_SIO_SET_DATA_BITS(n) (n)
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
/*
@ -183,12 +183,12 @@ enum {
* B10..15 Reserved
*/
/* FTDI_SIO_MODEM_CTRL */
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH (1 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_DTR_LOW (0 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH (2 | ( FTDI_SIO_SET_RTS_MASK << 8))
#define FTDI_SIO_SET_RTS_LOW (0 | ( FTDI_SIO_SET_RTS_MASK << 8))
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH (1 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_DTR_LOW (0 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH (2 | ( FTDI_SIO_SET_RTS_MASK << 8))
#define FTDI_SIO_SET_RTS_LOW (0 | ( FTDI_SIO_SET_RTS_MASK << 8))
/*
@ -216,10 +216,10 @@ enum {
* XOFF character and the lValue field contains the XON character.
*/
/* FTDI_SIO_SET_FLOW_CTRL */
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS 0x1
#define FTDI_SIO_DTR_DSR_HS 0x2
#define FTDI_SIO_XON_XOFF_HS 0x4
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS 0x1
#define FTDI_SIO_DTR_DSR_HS 0x2
#define FTDI_SIO_XON_XOFF_HS 0x4
/*
@ -295,10 +295,10 @@ enum {
* FTDI_SIO_GET_MODEM_STATUS
* Retrieve the current value of the modem status register.
*/
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
@ -350,9 +350,9 @@ enum {
* B2..7 Length of message - (not including Byte 0)
*
*/
#define FTDI_PORT_MASK 0x0f
#define FTDI_MSR_MASK 0xf0
#define FTDI_GET_MSR(p) (((p)[0]) & FTDI_MSR_MASK)
#define FTDI_GET_LSR(p) ((p)[1])
#define FTDI_LSR_MASK (~0x60) /* interesting bits */
#define FTDI_OUT_TAG(len, port) (((len) << 2) | (port))
#define FTDI_PORT_MASK 0x0f
#define FTDI_MSR_MASK 0xf0
#define FTDI_GET_MSR(p) (((p)[0]) & FTDI_MSR_MASK)
#define FTDI_GET_LSR(p) ((p)[1])
#define FTDI_LSR_MASK (~0x60) /* interesting bits */
#define FTDI_OUT_TAG(len, port) (((len) << 2) | (port))

View File

@ -2,17 +2,17 @@ SubDir HAIKU_TOP src add-ons kernel drivers ports usb_serial ;
SetSubDirSupportedPlatformsBeOSCompatible ;
local defines = [ FDefines B_USB_USE_V2_MODULE ] ;
SubDirCcFlags $(defines) ;
SubDirC++Flags -fno-rtti ;
KernelAddon usb_serial :
driver.c
tracing.c
acm.c
prolific.c
ftdi.c
klsi.c
Driver.cpp
SerialDevice.cpp
Tracing.cpp
ACM.cpp
FTDI.cpp
KLSI.cpp
Prolific.cpp
;
AddResources usb_serial : usb_serial.rdef ;

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "KLSI.h"
#include <ByteOrder.h>
KLSIDevice::KLSIDevice(usb_device device, uint16 vendorID, uint16 productID,
const char *description)
: SerialDevice(device, vendorID, productID, description)
{
}
status_t
KLSIDevice::AddDevice(const usb_configuration_info *config)
{
TRACE_FUNCALLS("> KLSIDevice::AddDevice(%08x, %08x)\n", this, config);
int32 pipesSet = 0;
status_t status = ENODEV;
if (config->interface_count > 0) {
usb_interface_info *interface = config->interface[0].active;
for (size_t i = 0; i < interface->endpoint_count; i++) {
usb_endpoint_info *endpoint = &interface->endpoint[i];
if (endpoint->descr->attributes == USB_EP_ATTR_INTERRUPT) {
if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
SetControlPipe(endpoint->handle);
if (++pipesSet >= 3)
break;
}
} else if (endpoint->descr->attributes == USB_EP_ATTR_BULK) {
if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
SetReadPipe(endpoint->handle);
if (++pipesSet >= 3)
break;
} else {
SetWritePipe(endpoint->handle);
if (++pipesSet >= 3)
break;
}
}
}
}
if (pipesSet >= 3)
status = B_OK;
TRACE_FUNCRET("< KLSIDevice::AddDevice() returns: 0x%08x\n", status);
return status;
}
status_t
KLSIDevice::ResetDevice()
{
TRACE_FUNCALLS("> KLSIDevice::ResetDevice(%08x)\n", this);
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT,
KLSI_CONF_REQUEST,
KLSI_CONF_REQUEST_READ_ON, 0, 0, NULL, &length);
TRACE_FUNCRET("< KLSIDevice::ResetDevice() returns: 0x%08x\n", status);
return status;
}
status_t
KLSIDevice::SetLineCoding(usb_serial_line_coding *lineCoding)
{
TRACE_FUNCALLS("> KLSIDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n",
this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity,
lineCoding->databits);
uint8 rate;
switch (lineCoding->speed) {
case 300: rate = klsi_sio_b300; break;
case 600: rate = klsi_sio_b600; break;
case 1200: rate = klsi_sio_b1200; break;
case 2400: rate = klsi_sio_b2400; break;
case 4800: rate = klsi_sio_b4800; break;
case 9600: rate = klsi_sio_b9600; break;
case 19200: rate = klsi_sio_b19200; break;
case 38400: rate = klsi_sio_b38400; break;
case 57600: rate = klsi_sio_b57600; break;
case 115200: rate = klsi_sio_b115200; break;
default:
rate = klsi_sio_b19200;
TRACE_ALWAYS("= KLSIDevice::SetLineCoding(): Datarate: %d is not "
"supported by this hardware. Defaulted to %d\n",
lineCoding->speed, rate);
break;
}
uint8 codingPacket[5];
codingPacket[0] = 5; /* size */
codingPacket[1] = rate;
codingPacket[2] = lineCoding->databits; /* only 7,8 */
codingPacket[3] = 0; /* unknown */
codingPacket[4] = 1; /* unknown */
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT,
KLSI_SET_REQUEST, 0, 0,
sizeof(codingPacket), codingPacket, &length);
if (status != B_OK)
TRACE_ALWAYS("= KLSIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status);
TRACE_FUNCRET("< KLSIDevice::SetLineCoding() returns: 0x%08x\n", status);
return status;
}
void
KLSIDevice::OnRead(char **buffer, size_t *numBytes)
{
if (*numBytes <= 2) {
*numBytes = 0;
return;
}
size_t bytes = B_LENDIAN_TO_HOST_INT16(*(uint16 *)(*buffer));
*numBytes = MIN(bytes, *numBytes - 2);
*buffer += 2;
}
void
KLSIDevice::OnWrite(const char *buffer, size_t *numBytes)
{
if (*numBytes >= WriteBufferSize() - 2)
*numBytes = WriteBufferSize() - 2;
char *writeBuffer = WriteBuffer();
*((uint16 *)writeBuffer) = B_HOST_TO_LENDIAN_INT16(*numBytes);
memcpy(writeBuffer + 2, buffer, *numBytes);
*numBytes += 2;
}
void
KLSIDevice::OnClose()
{
TRACE_FUNCALLS("> KLSIDevice::OnClose(%08x)\n", this);
size_t length = 0;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
KLSI_CONF_REQUEST,
KLSI_CONF_REQUEST_READ_OFF, 0, 0,
NULL, &length);
TRACE_FUNCRET("< KLSIDevice::OnClose() returns: 0x%08x\n", status);
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003-2004 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_KLSI_H_
#define _USB_KLSI_H_
#include "SerialDevice.h"
/* supported vendor and product ids */
#define VENDOR_PALM 0x0830
#define VENDOR_KLSI 0x05e9
#define PRODUCT_PALM_CONNECT 0x0080
#define PRODUCT_KLSI_KL5KUSB105D 0x00c0
/* protocol defines */
#define KLSI_SET_REQUEST 0x01
#define KLSI_POLL_REQUEST 0x02
#define KLSI_CONF_REQUEST 0x03
#define KLSI_CONF_REQUEST_READ_ON 0x03
#define KLSI_CONF_REQUEST_READ_OFF 0x02
// not sure
#define KLSI_BUFFER_SIZE 64
enum {
klsi_sio_b115200 = 0,
klsi_sio_b57600 = 1,
klsi_sio_b38400 = 2,
klsi_sio_b19200 = 4,
klsi_sio_b9600 = 6,
/* unchecked */
klsi_sio_b4800 = 8,
klsi_sio_b2400 = 9,
klsi_sio_b1200 = 10,
klsi_sio_b600 = 11,
klsi_sio_b300 = 12
};
class KLSIDevice : public SerialDevice {
public:
KLSIDevice(usb_device device, uint16 vendorID,
uint16 productID, const char *description);
virtual status_t AddDevice(const usb_configuration_info *config);
virtual status_t ResetDevice();
virtual status_t SetLineCoding(usb_serial_line_coding *coding);
virtual void OnRead(char **buffer, size_t *numBytes);
virtual void OnWrite(const char *buffer, size_t *numBytes);
virtual void OnClose();
};
#endif //_USB_KLSI_H_

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "Prolific.h"
ProlificDevice::ProlificDevice(usb_device device, uint16 vendorID,
uint16 productID, const char *description)
: ACMDevice(device, vendorID, productID, description),
fIsHX(false)
{
}
status_t
ProlificDevice::AddDevice(const usb_configuration_info *config)
{
TRACE_FUNCALLS("> ProlificDevice::AddDevice(%08x, %08x)\n", this, config);
// check for device type.
// Linux checks for type 0, 1 and HX, but handles 0 and 1 the same.
// We'll just check for HX then.
const usb_device_descriptor *deviceDescriptor = NULL;
deviceDescriptor = gUSBModule->get_device_descriptor(Device());
if (deviceDescriptor) {
fIsHX = (deviceDescriptor->device_class != 0x02
&& deviceDescriptor->max_packet_size_0 == 0x40);
}
int32 pipesSet = 0;
status_t status = ENODEV;
if (config->interface_count > 0) {
usb_interface_info *interface = config->interface[0].active;
for (size_t i = 0; i < interface->endpoint_count; i++) {
usb_endpoint_info *endpoint = &interface->endpoint[i];
if (endpoint->descr->attributes == USB_EP_ATTR_INTERRUPT) {
if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
SetControlPipe(endpoint->handle);
pipesSet++;
}
}
}
/* They say that USB-RSAQ1 has 2 interfaces */
if (config->interface_count >= 2)
interface = config->interface[1].active;
for (size_t i = 0; i < interface->endpoint_count; i++) {
usb_endpoint_info *endpoint = &interface->endpoint[i];
if (endpoint->descr->attributes == USB_EP_ATTR_BULK) {
if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
SetReadPipe(endpoint->handle);
if (++pipesSet >= 3)
break;
} else {
SetWritePipe(endpoint->handle);
if (++pipesSet >= 3)
break;
}
}
}
if (pipesSet >= 3)
status = B_OK;
}
TRACE_FUNCRET("< ProlificDevice::AddDevice() returns: 0x%08x\n", status);
return status;
}
struct request_item {
bool out;
uint16 value;
uint16 index;
};
/* Linux sends all those, and it seems to work */
/* see drivers/usb/serial/pl2303.c */
static struct request_item prolific_reset_common[] = {
{ false, 0x8484, 0 },
{ true, 0x0404, 0 },
{ false, 0x8484, 0 },
{ false, 0x8383, 0 },
{ false, 0x8484, 0 },
{ true, 0x0404, 1 },
{ false, 0x8484, 0 },
{ false, 0x8383, 0 },
{ true, 0x0000, 1 },
{ true, 0x0001, 0 }
};
static struct request_item prolific_reset_common_hx[] = {
{ true, 2, 0x44 },
{ true, 8, 0 },
{ true, 0, 0 }
};
static struct request_item prolific_reset_common_nhx[] = {
{ true, 2, 0x24 }
};
status_t
ProlificDevice::SendRequestList(request_item *list, size_t length)
{
for (size_t i = 0; i < length; i++) {
char buffer[10];
size_t bufferLength = 1;
status_t status = gUSBModule->send_request(Device(),
USB_REQTYPE_VENDOR | (list[i].out ? USB_REQTYPE_DEVICE_OUT : USB_REQTYPE_DEVICE_IN),
PROLIFIC_SET_REQUEST,
list[i].value,
list[i].index,
list[i].out ? 0 : bufferLength,
list[i].out ? NULL : buffer,
&bufferLength);
TRACE(" ProlificDevice::SendRequestList(): request[%d]: 0x%08lx\n", i, status);
}
return B_OK;
}
status_t
ProlificDevice::ResetDevice()
{
TRACE_FUNCALLS("> ProlificDevice::ResetDevice(%08x)\n", this);
SendRequestList(prolific_reset_common, SIZEOF(prolific_reset_common));
if (fIsHX)
SendRequestList(prolific_reset_common_hx, SIZEOF(prolific_reset_common_hx));
else
SendRequestList(prolific_reset_common_nhx, SIZEOF(prolific_reset_common_nhx));
status_t status = B_OK; /* discard */
TRACE_FUNCRET("< ProlificDevice::ResetDevice() returns: 0x%08x\n", status);
return status;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003-2004 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_PROLIFIC_H_
#define _USB_PROLIFIC_H_
#include "ACM.h"
/* supported vendor and product ids */
#define VENDOR_PROLIFIC 0x067b
#define VENDOR_IODATA 0x04bb
#define VENDOR_ATEN 0x0557
#define VENDOR_TDK 0x04bf
#define VENDOR_RATOC 0x0584
#define VENDOR_ELECOM 0x056e
#define VENDOR_SOURCENEXT 0x0833
#define VENDOR_HAL 0x0b41
#define PRODUCT_IODATA_USBRSAQ 0x0a03
#define PRODUCT_PROLIFIC_RSAQ2 0x04bb
#define PRODUCT_ATEN_UC232A 0x2008
#define PRODUCT_PROLIFIC_PL2303 0x2303
#define PRODUCT_TDK_UHA6400 0x0117
#define PRODUCT_RATOC_REXUSB60 0xb000
#define PRODUCT_ELECOM_UCSGT 0x5003
#define PRODUCT_SOURCENEXT_KEIKAI8 0x039f
#define PRODUCT_SOURCENEXT_KEIKAI8_CHG 0x012e
#define PRODUCT_HAL_IMR001 0x0011
/* protocol defines */
#define PROLIFIC_SET_REQUEST 0x01
#define PROLIFIC_BUF_SIZE 256
struct request_item;
class ProlificDevice : public ACMDevice {
public:
ProlificDevice(usb_device device,
uint16 vendorID, uint16 productID,
const char *description);
virtual status_t AddDevice(const usb_configuration_info *config);
virtual status_t ResetDevice();
private:
status_t SendRequestList(request_item *list, size_t length);
bool fIsHX;
};
#endif //_USB_PROLIFIC_H_

View File

@ -0,0 +1,662 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "SerialDevice.h"
#include "USB3.h"
#include "ACM.h"
#include "FTDI.h"
#include "KLSI.h"
#include "Prolific.h"
SerialDevice::SerialDevice(usb_device device, uint16 vendorID,
uint16 productID, const char *description)
: fDevice(device),
fVendorID(vendorID),
fProductID(productID),
fDescription(description),
fControlPipe(0),
fReadPipe(0),
fWritePipe(0),
fBufferArea(-1),
fReadBuffer(NULL),
fReadBufferSize(0),
fWriteBuffer(NULL),
fWriteBufferSize(0),
fInterruptBuffer(NULL),
fInterruptBufferSize(0),
fDoneRead(-1),
fDoneWrite(-1),
fControlOut(0),
fInputStopped(false),
fDeviceThread(-1),
fStopDeviceThread(false)
{
memset(&fTTYFile, 0, sizeof(ttyfile));
memset(&fTTY, 0, sizeof(tty));
}
SerialDevice::~SerialDevice()
{
fStopDeviceThread = true;
gUSBModule->cancel_queued_transfers(fReadPipe);
gUSBModule->cancel_queued_transfers(fWritePipe);
gUSBModule->cancel_queued_transfers(fControlPipe);
if (fDoneRead >= B_OK)
delete_sem(fDoneRead);
if (fDoneWrite >= B_OK)
delete_sem(fDoneWrite);
int32 result = B_OK;
wait_for_thread(fDeviceThread, &result);
if (fBufferArea >= B_OK)
delete_area(fBufferArea);
benaphore_destroy(&fReadLock);
benaphore_destroy(&fWriteLock);
}
status_t
SerialDevice::Init()
{
fDoneRead = create_sem(0, "usb_serial:done_read");
fDoneWrite = create_sem(0, "usb_serial:done_write");
benaphore_init(&fReadLock, "usb_serial:read_lock");
benaphore_init(&fWriteLock, "usb_serial:write_lock");
fReadBufferSize = fWriteBufferSize = ROUNDUP(DEF_BUFFER_SIZE, 16);
fInterruptBufferSize = 16;
size_t totalBuffers = fReadBufferSize + fWriteBufferSize + fInterruptBufferSize;
fBufferArea = create_area("usb_serial:buffers_area", (void **)&fReadBuffer,
B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), B_CONTIGUOUS,
B_READ_AREA | B_WRITE_AREA);
fWriteBuffer = fReadBuffer + fReadBufferSize;
fInterruptBuffer = fWriteBuffer + fWriteBufferSize;
return B_OK;
}
void
SerialDevice::SetControlPipe(usb_pipe handle)
{
fControlPipe = handle;
}
void
SerialDevice::SetReadPipe(usb_pipe handle)
{
fReadPipe = handle;
}
void
SerialDevice::SetWritePipe(usb_pipe handle)
{
fWritePipe = handle;
}
void
SerialDevice::SetModes()
{
struct termios tios;
memcpy(&tios, &fTTY.t, sizeof(struct termios));
uint16 newControl = fControlOut;
TRACE_FUNCRES(trace_termios, &tios);
static uint32 baudRates[] = {
0x00000000, //B0
0x00000032, //B50
0x0000004B, //B75
0x0000006E, //B110
0x00000086, //B134
0x00000096, //B150
0x000000C8, //B200
0x0000012C, //B300
0x00000258, //B600
0x000004B0, //B1200
0x00000708, //B1800
0x00000960, //B2400
0x000012C0, //B4800
0x00002580, //B9600
0x00004B00, //B19200
0x00009600, //B38400
0x0000E100, //B57600
0x0001C200, //B115200
0x00038400, //B230400
0x00070800, //460800
0x000E1000, //921600
};
uint32 baudCount = sizeof(baudRates) / sizeof(baudRates[0]);
uint32 baudIndex = tios.c_cflag & CBAUD;
if (baudIndex > baudCount)
baudIndex = baudCount - 1;
usb_serial_line_coding lineCoding;
lineCoding.speed = baudRates[baudIndex];
lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
if (tios.c_cflag & PARENB) {
lineCoding.parity = LC_PARITY_EVEN;
if (tios.c_cflag & PARODD)
lineCoding.parity = LC_PARITY_ODD;
} else
lineCoding.parity = LC_PARITY_NONE;
lineCoding.databits = (tios.c_cflag & CS8) ? 8 : 7;
if (lineCoding.speed == 0) {
newControl &= 0xfffffffe;
lineCoding.speed = fLineCoding.speed;
} else
newControl = CLS_LINE_DTR;
if (fControlOut != newControl) {
fControlOut = newControl;
TRACE("newctrl send to modem: 0x%08x\n", newControl);
SetControlLineState(newControl);
}
if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) {
fLineCoding.speed = lineCoding.speed;
fLineCoding.stopbits = lineCoding.stopbits;
fLineCoding.databits = lineCoding.databits;
fLineCoding.parity = lineCoding.parity;
TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n",
fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits,
fLineCoding.parity);
SetLineCoding(&fLineCoding);
}
}
bool
SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags)
{
if (&fTTY != ptty)
return false;
if (flags <= TTYGETSIGNALS) {
switch (flags) {
case TTYENABLE:
TRACE("TTYENABLE\n");
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
SetControlLineState(fControlOut);
break;
case TTYDISABLE:
TRACE("TTYDISABLE\n");
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
fControlOut = 0x0;
SetControlLineState(fControlOut);
break;
case TTYISTOP:
TRACE("TTYISTOP\n");
fInputStopped = true;
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
break;
case TTYIRESUME:
TRACE("TTYIRESUME\n");
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
fInputStopped = false;
break;
case TTYGETSIGNALS:
TRACE("TTYGETSIGNALS\n");
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, true);
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, false);
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, false);
break;
case TTYSETMODES:
TRACE("TTYSETMODES\n");
SetModes();
break;
case TTYOSTART:
case TTYOSYNC:
case TTYSETBREAK:
case TTYCLRBREAK:
case TTYSETDTR:
case TTYCLRDTR:
TRACE("TTY other\n");
break;
}
return true;
}
return false;
}
status_t
SerialDevice::Open(uint32 flags)
{
gTTYModule->ttyinit(&fTTY, true);
fTTYFile.tty = &fTTY;
fTTYFile.flags = flags;
ResetDevice();
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
gTTYModule->ddacquire(ddr, &gSerialDomain);
status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, usb_serial_service);
gTTYModule->ddrdone(ddr);
if (status < B_OK) {
TRACE_ALWAYS("open: failed to open tty\n");
return status;
}
fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread",
B_NORMAL_PRIORITY, this);
if (fDeviceThread < B_OK) {
TRACE_ALWAYS("open: failed to spawn kernel thread\n");
return fDeviceThread;
}
resume_thread(fDeviceThread);
fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
SetControlLineState(fControlOut);
status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer,
fInterruptBufferSize, InterruptCallbackFunction, this);
if (status < B_OK)
TRACE_ALWAYS("failed to queue initial interrupt\n");
return status;
}
status_t
SerialDevice::Read(char *buffer, size_t *numBytes)
{
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr) {
*numBytes = 0;
return B_NO_MEMORY;
}
status_t status = benaphore_lock(&fReadLock);
if (status != B_OK) {
TRACE_ALWAYS("read: failed to get read lock\n");
*numBytes = 0;
return status;
}
status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes);
gTTYModule->ddrdone(ddr);
benaphore_unlock(&fReadLock);
return status;
}
status_t
SerialDevice::Write(const char *buffer, size_t *numBytes)
{
size_t bytesLeft = *numBytes;
*numBytes = 0;
status_t status = benaphore_lock(&fWriteLock);
if (status != B_OK) {
TRACE_ALWAYS("write: failed to get write lock\n");
return status;
}
while (bytesLeft > 0) {
size_t length = MIN(bytesLeft, fWriteBufferSize);
OnWrite(buffer, &length);
status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer,
length, WriteCallbackFunction, this);
if (status < B_OK) {
TRACE_ALWAYS("write: queueing failed with status 0x%08x\n", status);
break;
}
status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0);
if (status < B_OK) {
TRACE_ALWAYS("write: failed to get write done sem 0x%08x\n", status);
break;
}
if (fStatusWrite != B_OK) {
TRACE("write: device status error 0x%08x\n", fStatusWrite);
status = gUSBModule->clear_feature(fWritePipe,
USB_FEATURE_ENDPOINT_HALT);
if (status < B_OK) {
TRACE_ALWAYS("write: failed to clear device halt\n");
status = B_ERROR;
break;
}
continue;
}
buffer += fActualLengthWrite;
*numBytes += fActualLengthWrite;
bytesLeft -= fActualLengthWrite;
}
benaphore_unlock(&fWriteLock);
return status;
}
status_t
SerialDevice::Control(uint32 op, void *arg, size_t length)
{
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
status_t status = gTTYModule->ttycontrol(&fTTYFile, ddr, op, arg, length);
gTTYModule->ddrdone(ddr);
return status;
}
status_t
SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync)
{
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
status_t status = gTTYModule->ttyselect(&fTTYFile, ddr, event, ref, sync);
gTTYModule->ddrdone(ddr);
return status;
}
status_t
SerialDevice::DeSelect(uint8 event, selectsync *sync)
{
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
status_t status = gTTYModule->ttydeselect(&fTTYFile, ddr, event, sync);
gTTYModule->ddrdone(ddr);
return status;
}
status_t
SerialDevice::Close()
{
OnClose();
gUSBModule->cancel_queued_transfers(fReadPipe);
gUSBModule->cancel_queued_transfers(fWritePipe);
gUSBModule->cancel_queued_transfers(fControlPipe);
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
status_t status = gTTYModule->ttyclose(&fTTYFile, ddr);
gTTYModule->ddrdone(ddr);
return status;
}
status_t
SerialDevice::Free()
{
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr)
return B_NO_MEMORY;
status_t status = gTTYModule->ttyfree(&fTTYFile, ddr);
gTTYModule->ddrdone(ddr);
return status;
}
status_t
SerialDevice::AddDevice(const usb_configuration_info *config)
{
// default implementation - does nothing
return B_ERROR;
}
status_t
SerialDevice::ResetDevice()
{
// default implementation - does nothing
return B_OK;
}
status_t
SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
{
// default implementation - does nothing
return B_OK;
}
status_t
SerialDevice::SetControlLineState(uint16 state)
{
// default implementation - does nothing
return B_OK;
}
void
SerialDevice::OnRead(char **buffer, size_t *numBytes)
{
// default implementation - does nothing
}
void
SerialDevice::OnWrite(const char *buffer, size_t *numBytes)
{
// default implementation - does nothing
}
void
SerialDevice::OnClose()
{
// default implementation - does nothing
}
int32
SerialDevice::DeviceThread(void *data)
{
SerialDevice *device = (SerialDevice *)data;
while (!device->fStopDeviceThread) {
status_t status = gUSBModule->queue_bulk(device->fReadPipe,
device->fReadBuffer, device->fReadBufferSize,
device->ReadCallbackFunction, data);
if (status < B_OK) {
TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status);
break;
}
status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0);
if (status < B_OK) {
TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status);
break;
}
if (device->fStatusRead != B_OK) {
TRACE("device thread: device status error 0x%08x\n",
device->fStatusRead);
if (gUSBModule->clear_feature(device->fReadPipe,
USB_FEATURE_ENDPOINT_HALT) != B_OK) {
TRACE_ALWAYS("device thread: failed to clear halt feature\n");
break;
}
}
char *buffer = device->fReadBuffer;
size_t readLength = device->fActualLengthRead;
device->OnRead(&buffer, &readLength);
if (readLength == 0)
continue;
ddrover *ddr = gTTYModule->ddrstart(NULL);
if (!ddr) {
TRACE_ALWAYS("device thread: ddrstart problem\n");
return B_NO_MEMORY;
}
while (device->fInputStopped)
snooze(100);
gTTYModule->ttyilock(&device->fTTY, ddr, true);
for (size_t i = 0; i < readLength; i++)
gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]);
gTTYModule->ttyilock(&device->fTTY, ddr, false);
gTTYModule->ddrdone(ddr);
}
return B_OK;
}
void
SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data,
uint32 actualLength)
{
TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
cookie, status, data, actualLength);
SerialDevice *device = (SerialDevice *)cookie;
device->fActualLengthRead = actualLength;
device->fStatusRead = status;
release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE);
}
void
SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data,
uint32 actualLength)
{
TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
cookie, status, data, actualLength);
SerialDevice *device = (SerialDevice *)cookie;
device->fActualLengthWrite = actualLength;
device->fStatusWrite = status;
release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE);
}
void
SerialDevice::InterruptCallbackFunction(void *cookie, int32 status,
void *data, uint32 actualLength)
{
TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
cookie, status, data, actualLength);
SerialDevice *device = (SerialDevice *)cookie;
device->fActualLengthInterrupt = actualLength;
device->fStatusInterrupt = status;
// ToDo: maybe handle those somehow?
if (status == B_OK) {
status = gUSBModule->queue_interrupt(device->fControlPipe,
device->fInterruptBuffer, device->fInterruptBufferSize,
device->InterruptCallbackFunction, device);
}
}
SerialDevice *
SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
uint16 productID)
{
const char *description = NULL;
switch (vendorID) {
case VENDOR_IODATA:
case VENDOR_ATEN:
case VENDOR_TDK:
case VENDOR_RATOC:
case VENDOR_PROLIFIC:
case VENDOR_ELECOM:
case VENDOR_SOURCENEXT:
case VENDOR_HAL:
{
switch (productID) {
case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break;
case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break;
case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break;
case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break;
case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break;
case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break;
case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break;
case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break;
case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break;
case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break;
}
if (!description)
break;
return new ProlificDevice(device, vendorID, productID, description);
}
case VENDOR_FTDI:
{
switch (productID) {
case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break;
case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break;
}
if (!description)
break;
return new FTDIDevice(device, vendorID, productID, description);
}
case VENDOR_PALM:
case VENDOR_KLSI:
{
switch (productID) {
case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break;
case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break;
}
if (!description)
break;
return new KLSIDevice(device, vendorID, productID, description);
}
}
return new ACMDevice(device, vendorID, productID, "CDC ACM compatible device");
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_DEVICE_H_
#define _USB_DEVICE_H_
#include "Driver.h"
class SerialDevice {
public:
SerialDevice(usb_device device,
uint16 vendorID, uint16 productID,
const char *description);
virtual ~SerialDevice();
static SerialDevice * MakeDevice(usb_device device, uint16 vendorID,
uint16 productID);
status_t Init();
usb_device Device() { return fDevice; };
uint16 ProductID() { return fProductID; };
uint16 VendorID() { return fVendorID; };
const char * Description() { return fDescription; };
void SetControlPipe(usb_pipe handle);
usb_pipe ControlPipe() { return fControlPipe; };
void SetReadPipe(usb_pipe handle);
usb_pipe ReadPipe() { return fReadPipe; };
void SetWritePipe(usb_pipe handle);
usb_pipe WritePipe() { return fWritePipe; }
char * ReadBuffer() { return fReadBuffer; };
size_t ReadBufferSize() { return fReadBufferSize; };
char * WriteBuffer() { return fWriteBuffer; };
size_t WriteBufferSize() { return fWriteBufferSize; };
void SetModes();
bool Service(struct tty *ptty, struct ddrover *ddr,
uint flags);
status_t Open(uint32 flags);
status_t Read(char *buffer, size_t *numBytes);
status_t Write(const char *buffer, size_t *numBytes);
status_t Control(uint32 op, void *arg, size_t length);
status_t Select(uint8 event, uint32 ref, selectsync *sync);
status_t DeSelect(uint8 event, selectsync *sync);
status_t Close();
status_t Free();
/* virtual interface to be overriden as necessary */
virtual status_t AddDevice(const usb_configuration_info *config);
virtual status_t ResetDevice();
virtual status_t SetLineCoding(usb_serial_line_coding *coding);
virtual status_t SetControlLineState(uint16 state);
virtual void OnRead(char **buffer, size_t *numBytes);
virtual void OnWrite(const char *buffer, size_t *numBytes);
virtual void OnClose();
private:
static int32 DeviceThread(void *data);
static void ReadCallbackFunction(void *cookie,
int32 status, void *data,
uint32 actualLength);
static void WriteCallbackFunction(void *cookie,
int32 status, void *data,
uint32 actualLength);
static void InterruptCallbackFunction(void *cookie,
int32 status, void *data,
uint32 actualLength);
usb_device fDevice; // USB device handle
uint16 fVendorID;
uint16 fProductID;
const char * fDescription; // informational description
/* communication pipes */
usb_pipe fControlPipe;
usb_pipe fReadPipe;
usb_pipe fWritePipe;
/* line coding */
usb_serial_line_coding fLineCoding;
/* data buffers */
area_id fBufferArea;
char * fReadBuffer;
size_t fReadBufferSize;
char * fWriteBuffer;
size_t fWriteBufferSize;
char * fInterruptBuffer;
size_t fInterruptBufferSize;
/* variables used in callback functionality */
size_t fActualLengthRead;
uint32 fStatusRead;
size_t fActualLengthWrite;
uint32 fStatusWrite;
size_t fActualLengthInterrupt;
uint32 fStatusInterrupt;
/* semaphores used in callbacks */
sem_id fDoneRead;
sem_id fDoneWrite;
uint16 fControlOut;
bool fInputStopped;
struct ttyfile fTTYFile;
struct tty fTTY;
/* device thread management */
thread_id fDeviceThread;
bool fStopDeviceThread;
/* device locks to ensure no concurent reads/writes */
benaphore fReadLock;
benaphore fWriteLock;
};
#endif // _USB_DEVICE_H_

View File

@ -0,0 +1,188 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#include "Tracing.h"
#include "Driver.h"
#include "USB3.h"
extern "C" {
#include <ttylayer.h>
}
#include <stdio.h> //sprintf
#include <unistd.h> //posix file i/o - create, write, close
#include <Drivers.h>
#include <driver_settings.h>
#if DEBUG
bool gLogEnabled = true;
#else
bool gLogEnabled = false;
#endif
bool gLogToFile = false;
bool gLogAppend = false;
bool gLogFunctionCalls = false;
bool gLogFunctionReturns = false;
bool gLogFunctionResults = false;
static const char *sLogFilePath="/boot/home/"DRIVER_NAME".log";
static sem_id sLogLock;
void
load_settings()
{
void *settingsHandle;
settingsHandle = load_driver_settings(DRIVER_NAME);
#if !DEBUG
gLogEnabled = get_driver_boolean_parameter(settingsHandle,
"debug_output", gLogEnabled, true);
#endif
gLogToFile = get_driver_boolean_parameter(settingsHandle,
"debug_output_in_file", gLogToFile, true);
gLogAppend = !get_driver_boolean_parameter(settingsHandle,
"debug_output_file_rewrite", !gLogAppend, true);
gLogFunctionCalls = get_driver_boolean_parameter(settingsHandle,
"debug_trace_func_calls", gLogFunctionCalls, false);
gLogFunctionReturns = get_driver_boolean_parameter(settingsHandle,
"debug_trace_func_returns", gLogFunctionReturns, false);
gLogFunctionResults = get_driver_boolean_parameter(settingsHandle,
"debug_trace_func_results", gLogFunctionResults, false);
unload_driver_settings(settingsHandle);
}
void
create_log_file()
{
if(!gLogToFile)
return;
int flags = O_WRONLY | O_CREAT | (!gLogAppend ? O_TRUNC : 0);
close(open(sLogFilePath, flags, 0666));
sLogLock = create_sem(1, DRIVER_NAME"-logging");
}
void
usb_serial_trace(bool force, char *format, ...)
{
if (!gLogEnabled && !force)
return;
static char buffer[1024];
char *bufferPointer = buffer;
if (!gLogToFile) {
const char *prefix = "\33[32m"DRIVER_NAME":\33[0m ";
strcpy(bufferPointer, prefix);
bufferPointer += strlen(prefix);
}
va_list argumentList;
va_start(argumentList, format);
vsprintf(bufferPointer, format, argumentList);
va_end(argumentList);
if (gLogToFile) {
acquire_sem(sLogLock);
int fd = open(sLogFilePath, O_WRONLY | O_APPEND);
write(fd, buffer, strlen(buffer));
close(fd);
release_sem(sLogLock);
} else
dprintf(buffer);
}
void
trace_ddomain(struct ddomain *dd)
{
TRACE("struct ddomain:\n"
"\tddrover: 0x%08x\n"
"\tbg: %d, locked: %d\n", dd->r, dd->bg, dd->locked);
}
void
trace_termios(struct termios *tios)
{
TRACE("struct termios:\n"
"\tc_iflag: 0x%08x\n"
"\tc_oflag: 0x%08x\n"
"\tc_cflag: 0x%08x\n"
"\tc_lflag: 0x%08x\n"
"\tc_line: 0x%08x\n"
"\tc_ixxxxx: 0x%08x\n"
"\tc_oxxxxx: 0x%08x\n"
"\tc_cc[0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x]\n",
tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag,
tios->c_line, tios->c_ixxxxx, tios->c_oxxxxx, tios->c_cc[0],
tios->c_cc[1], tios->c_cc[2], tios->c_cc[3], tios->c_cc[4],
tios->c_cc[5], tios->c_cc[6], tios->c_cc[7], tios->c_cc[8],
tios->c_cc[9], tios->c_cc[10]);
}
void
trace_str(struct str *str)
{
TRACE("struct str:\n"
"\tbuffer: 0x%08x\n"
"\tbufsize: %d\n"
"\tcount: %d\n"
"\ttail: %d\n"
"\tallocated: %d\n",
str->buffer, str->bufsize, str->count, str->tail, str->allocated);
}
void
trace_winsize(struct winsize *ws)
{
TRACE("struct winsize:\n"
"\tws_row: %d\n"
"\tws_col: %d\n"
"\tws_xpixel: %d\n"
"\tws_ypixel: %d\n",
ws->ws_row, ws->ws_col, ws->ws_xpixel, ws->ws_ypixel);
}
void
trace_tty(struct tty *tty)
{
TRACE("struct tty:\n"
"\tnopen: %d, flags: 0x%08x,\n", tty->nopen, tty->flags);
TRACE("ddomain dd:\n");
trace_ddomain(&tty->dd);
TRACE("ddomain ddi:\n");
trace_ddomain(&tty->ddi);
TRACE("\tpgid: %08x\n", tty->pgid);
TRACE("termios t:");
trace_termios(&tty->t);
TRACE("\tiactivity: %d, ibusy: %d\n", tty->iactivity, tty->ibusy);
TRACE("str istr:\n");
trace_str(&tty->istr);
TRACE("str rstr:\n");
trace_str(&tty->rstr);
TRACE("str ostr:\n");
trace_str(&tty->ostr);
TRACE("winsize wsize:\n");
trace_winsize(&tty->wsize);
TRACE("\tservice: 0x%08x\n", tty->service);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2007-2008 by Michael Lotz
* Heavily based on the original usb_serial driver which is:
*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_SERIAL_TRACING_H_
#define _USB_SERIAL_TRACING_H_
void load_settings();
void create_log_file();
void usb_serial_trace(bool force, char *format, ...);
#define TRACE_ALWAYS(x...) usb_serial_trace(true, x);
#define TRACE(x...) usb_serial_trace(false, x);
extern bool gLogFunctionCalls;
#define TRACE_FUNCALLS(x...) \
if (gLogFunctionCalls) \
usb_serial_trace(false, x);
extern bool gLogFunctionReturns;
#define TRACE_FUNCRET(x...) \
if (gLogFunctionReturns) \
usb_serial_trace(false, x);
extern bool gLogFunctionResults;
#define TRACE_FUNCRES(func, param) \
if (gLogFunctionResults) \
func(param);
void trace_ddomain(struct ddomain *dd);
void trace_termios(struct termios *tios);
void trace_str(struct str *str);
void trace_winsize(struct winsize *ws);
void trace_tty(struct tty *tty);
#endif //_USB_SERIAL_TRACING_H_

View File

@ -0,0 +1,227 @@
/*
* Version 3 USB Device Driver API
*
* Copyright 2006, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _USB_V3_H_
#define _USB_V3_H_
#include <KernelExport.h>
#include <bus_manager.h>
#include <iovec.h>
#include <USB_spec.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct usb_module_info usb_module_info;
typedef uint32 usb_id;
typedef usb_id usb_device;
typedef usb_id usb_interface;
typedef usb_id usb_pipe;
typedef struct usb_endpoint_info usb_endpoint_info;
typedef struct usb_interface_info usb_interface_info;
typedef struct usb_interface_list usb_interface_list;
typedef struct usb_configuration_info usb_configuration_info;
typedef struct usb_notify_hooks {
status_t (*device_added)(usb_device device, void **cookie);
status_t (*device_removed)(void *cookie);
} usb_notify_hooks;
typedef struct usb_support_descriptor {
uint8 dev_class;
uint8 dev_subclass;
uint8 dev_protocol;
uint16 vendor;
uint16 product;
} usb_support_descriptor;
struct usb_endpoint_info {
usb_endpoint_descriptor *descr; /* descriptor and handle */
usb_pipe handle; /* of this endpoint/pipe */
};
struct usb_interface_info {
usb_interface_descriptor *descr; /* descriptor and handle */
usb_interface handle; /* of this interface */
size_t endpoint_count; /* count and list of endpoints */
usb_endpoint_info *endpoint; /* in this interface */
size_t generic_count; /* unparsed descriptors in */
usb_descriptor **generic; /* this interface */
};
struct usb_interface_list {
size_t alt_count; /* count and list of alternate */
usb_interface_info *alt; /* interfaces available */
usb_interface_info *active; /* currently active alternate */
};
struct usb_configuration_info {
usb_configuration_descriptor *descr; /* descriptor of this config */
size_t interface_count;/* interfaces in this config */
usb_interface_list *interface;
};
typedef struct {
int16 request_length;
int16 actual_length;
status_t status;
} usb_iso_packet_descriptor;
// Flags for queue_isochronous
#define USB_ISO_ASAP 0x01
typedef void (*usb_callback_func)(void *cookie, status_t status, void *data,
size_t actualLength);
/* The usb_module_info represents the public API of the USB Stack. */
struct usb_module_info {
bus_manager_info binfo;
/*
* Use register_driver() to inform the Stack of your interest to support
* USB devices. Support descriptors are used to indicate support for a
* specific device class/subclass/protocol or vendor/product.
* A value of 0 can be used as a wildcard for all fields.
*
* Would you like to be notified about all added hubs (class 0x09) you
* would use a support descriptor like this for register_driver:
* usb_support_descriptor hub_devs = { 9, 0, 0, 0, 0 };
*
* If you intend to support just any device, or you at least want to be
* notified about any device, just pass NULL as the supportDescriptor and
* 0 as the supportDescriptorCount to register_driver.
*/
status_t (*register_driver)(const char *driverName,
const usb_support_descriptor *supportDescriptors,
size_t supportDescriptorCount,
const char *optionalRepublishDriverName);
/*
* Install notification hooks using your registered driverName. The
* device_added hook will be called for every device that matches the
* support descriptors you provided in register_driver.
* When first installing the hooks you will receive a notification about
* any already present matching device. If you return B_OK in this hook,
* you can use the id that is provided. If the hook indicates an error,
* the resources will be deallocated and you may not use the usb_device
* that is provided. In this case you will not receive a device_removed
* notification for the device either.
*/
status_t (*install_notify)(const char *driverName,
const usb_notify_hooks *hooks);
status_t (*uninstall_notify)(const char *driverName);
/* Get the device descriptor of a device. */
const usb_device_descriptor *(*get_device_descriptor)(usb_device device);
/* Get the nth supported configuration of a device*/
const usb_configuration_info *(*get_nth_configuration)(usb_device device,
uint index);
/* Get the current configuration */
const usb_configuration_info *(*get_configuration)(usb_device device);
/* Set the current configuration */
status_t (*set_configuration)(usb_device device,
const usb_configuration_info *configuration);
status_t (*set_alt_interface)(usb_device device,
const usb_interface_info *interface);
/*
* Standard device requests - convenience functions
* The provided handle may be a usb_device, usb_pipe or usb_interface
*/
status_t (*set_feature)(usb_id handle, uint16 selector);
status_t (*clear_feature)(usb_id handle, uint16 selector);
status_t (*get_status)(usb_id handle, uint16 *status);
status_t (*get_descriptor)(usb_device device,
uint8 descriptorType, uint8 index,
uint16 languageID, void *data,
size_t dataLength,
size_t *actualLength);
/* Generic device request function - synchronous */
status_t (*send_request)(usb_device device,
uint8 requestType, uint8 request,
uint16 value, uint16 index,
uint16 length, void *data,
size_t *actualLength);
/*
* Asynchronous request queueing. These functions return immediately
* and the return code only tells whether the _queuing_ of the request
* was successful or not. It doesn't indicate transfer success or error.
*
* When the transfer is finished, the provided callback function is
* called with the transfer status, a pointer to the data buffer and
* the actually transfered length as well as with the callbackCookie
* that was used when queuing the request.
*/
status_t (*queue_interrupt)(usb_pipe pipe,
void *data, size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
status_t (*queue_bulk)(usb_pipe pipe,
void *data, size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
status_t (*queue_bulk_v)(usb_pipe pipe,
iovec *vector, size_t vectorCount,
usb_callback_func callback,
void *callbackCookie);
status_t (*queue_isochronous)(usb_pipe pipe,
void *data, size_t dataLength,
usb_iso_packet_descriptor *packetDesc,
uint32 packetCount,
uint32 *startingFrameNumber,
uint32 flags,
usb_callback_func callback,
void *callbackCookie);
status_t (*queue_request)(usb_device device,
uint8 requestType, uint8 request,
uint16 value, uint16 index,
uint16 length, void *data,
usb_callback_func callback,
void *callbackCookie);
status_t (*set_pipe_policy)(usb_pipe pipe,
uint8 maxNumQueuedPackets,
uint16 maxBufferDurationMS,
uint16 sampleSize);
/* Cancel all pending async requests in a pipe */
status_t (*cancel_queued_transfers)(usb_pipe pipe);
/* tuning, timeouts, etc */
status_t (*usb_ioctl)(uint32 opcode, void *buffer,
size_t bufferSize);
};
#define B_USB_MODULE_NAME "bus_managers/usb/v3"
#ifdef __cplusplus
}
#endif
#endif /* !_USB_V3_H_ */

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <USB.h>
#include <ttylayer.h>
#include "driver.h"
#include "acm.h"
status_t add_acm_device(usb_serial_device *usd,
const usb_configuration_info *uci)
{
struct usb_endpoint_info *comm_epi = NULL;
struct usb_endpoint_info *data_out_epi = NULL;
struct usb_endpoint_info *data_in_epi = NULL;
status_t status = ENODEV;
int i = 0;
TRACE_FUNCALLS("> add_acm_device(%08x, %08x)\n", usd, uci);
for(i=0; i < uci->interface_count; i++){
usb_interface_descriptor *uid =
uci->interface[i].active->descr;
if(uid->interface_class == USB_INT_CLASS_CDC &&
uid->interface_subclass == USB_INT_SUBCLASS_ABSTRACT_CONTROL_MODEL &&
uid->num_endpoints == 1){
comm_epi = uci->interface[i].active->endpoint;
}
if(uid->interface_class == USB_INT_CLASS_CDC_DATA &&
(uid->interface_subclass == 2 || // ?????????????
uid->interface_subclass == USB_INT_SUBCLASS_DATA)){
if(uid->num_endpoints == 2){
data_out_epi = &uci->interface[i].active->endpoint[0];
data_in_epi = &uci->interface[i].active->endpoint[1];
}
}
if(comm_epi && data_out_epi && data_in_epi)
break;
}
if(comm_epi && data_out_epi && data_in_epi){
status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi);
}
TRACE_FUNCRET("< add_acm_device returns:%08x\n", status);
return status;
}
status_t reset_acm_device(usb_serial_device *usd){
status_t status = B_OK;
TRACE_FUNCALLS("> reset_acm_device(%08x)\n", usd);
TRACE_FUNCRET("< reset_acm_device returns:%08x\n", status);
return status;
}
status_t set_line_coding_acm(usb_serial_device *usd,
usb_serial_line_coding *line_coding){
size_t len = 0;
status_t status = B_OK;
TRACE_FUNCALLS("> set_line_coding_acm(%08x, {%d, %02x, %02x, %02x})\n",
usd, line_coding->speed,
line_coding->stopbits,
line_coding->parity,
line_coding->databits);
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
SET_LINE_CODING, 0x0, 0x0,
sizeof(usb_serial_line_coding),
line_coding,
sizeof(usb_serial_line_coding), &len);
TRACE_FUNCRET("< set_line_coding_acm returns:%08x\n", status);
return status;
}
status_t set_control_line_state_acm(usb_serial_device *usd, uint16 state){
size_t len = 0;
status_t status = B_OK;
TRACE_FUNCALLS("> set_control_line_state_acm(%08x, %04x)\n", usd, state);
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
SET_CONTROL_LINE_STATE, state, 0, 0, 0, 0,
&len);
TRACE_FUNCRET("< set_control_line_state_acm returns:%08x\n", status);
return status;
}
void on_read_acm(usb_serial_device *usd, char **buf, size_t *num_bytes){
}
void on_write_acm(usb_serial_device *usd, const char *buf, size_t *num_bytes){
if(*num_bytes > usd->write_buffer_size)
*num_bytes = usd->write_buffer_size;
memcpy(usd->write_buffer, buf, *num_bytes);
}
void on_close_acm(usb_serial_device *usd){
TRACE_FUNCALLS("> add_acm_device(%08x)\n", usd);
(*usb_m->cancel_queued_transfers)(usd->pipe_read);
(*usb_m->cancel_queued_transfers)(usd->pipe_write);
(*usb_m->cancel_queued_transfers)(usd->pipe_control);
}

View File

@ -1,20 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_ACM_H_
#define _USB_ACM_H_
status_t add_acm_device(usb_serial_device *usd,
const usb_configuration_info *uci);
status_t reset_acm_device(usb_serial_device *usd);
status_t set_line_coding_acm(usb_serial_device *usd,
usb_serial_line_coding *line_coding);
status_t set_control_line_state_acm(usb_serial_device *usd, uint16 state);
void on_read_acm(usb_serial_device *usd, char **buf, size_t *num_bytes);
void on_write_acm(usb_serial_device *usd, const char *buf, size_t *num_bytes);
void on_close_acm(usb_serial_device *usd);
#endif //_USB_ACM_H_

View File

@ -1,945 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <USB.h>
#include <ttylayer.h>
#include <malloc.h>
#include <string.h> /* strerror */
#include <stdlib.h> /* strtol */
#include <stdio.h> /* sprintf */
#include "driver.h"
#include "acm.h"
#include "prolific.h"
#include "ftdi.h"
#include "klsi.h"
/* driver callbacks forward declarations */
static status_t usb_serial_open (const char *name, uint32 flags, void** cookie);
static status_t usb_serial_read (void* cookie,
off_t position, void *buf, size_t* num_bytes);
static status_t usb_serial_write (void* cookie, off_t position,
const void* buffer, size_t* num_bytes);
static status_t usb_serial_select (void* cookie, uint8 event, uint32 ref, selectsync *_sync);
static status_t usb_serial_deselect (void* cookie, uint8 event, selectsync *_sync);
static status_t usb_serial_control (void* cookie, uint32 op, void* arg, size_t len);
static status_t usb_serial_close (void* cookie);
static status_t usb_serial_free (void* cookie);
/* USB notify callbacks forward declarations */
status_t usb_serial_device_added(const usb_device *dev, void **cookie);
status_t usb_serial_device_removed(void *cookie);
/* The base name of drivers created in /dev/ports/ directory */
#define BASENAME_LEN 0x09 /*must be synchronized with below !!!*/
static const char *basename = "ports/usb%u";
/* function pointers for the device hooks entry points */
device_hooks usb_serial_hooks = {
usb_serial_open, /* -> open entry point */
usb_serial_close, /* -> close entry point */
usb_serial_free, /* -> free cookie */
usb_serial_control, /* -> control entry point */
usb_serial_read, /* -> read entry point */
usb_serial_write, /* -> write entry point */
#if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
usb_serial_select, /* -> select entry point */
usb_serial_deselect /* -> deselect entry point */
#endif
/* readv / read_pages ??? */
/* writev */
};
/* USB notify hooks */
static usb_notify_hooks notify_hooks = {
&usb_serial_device_added,
&usb_serial_device_removed
};
/* kernel modules */
usb_module_info *usb_m; /* usb layer */
tty_module_info *tty_m; /* tty layer */
struct tty usb_serial_tty[DEVICES_COUNT];
struct ddomain usb_serial_dd;
/* hardware devices, supported by this driver.
See description field for human readable names */
usb_serial_hw usb_serial_hw_devices[] = {
{0, 0, add_acm_device, reset_acm_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"CDC ACM compatible device"},
{VND_PROLIFIC, PROD_PROLIFIC_RSAQ2,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"PL2303 Serial adapter (IODATA USB-RSAQ2)"},
{VND_IODATA, PROD_IODATA_USBRSAQ,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"I/O Data USB serial adapter USB-RSAQ1"},
{VND_ATEN, PROD_ATEN_UC232A,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"Aten Serial adapter"},
{VND_TDK, PROD_TDK_UHA6400,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"TDK USB-PHS Adapter UHA6400"},
{VND_RATOC, PROD_RATOC_REXUSB60,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"Ratoc USB serial adapter REX-USB60"},
{VND_PROLIFIC, PROD_PROLIFIC_PL2303,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"PL2303 Serial adapter (ATEN/IOGEAR UC232A)"},
{VND_ELECOM, PROD_ELECOM_UCSGT,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"Elecom UC-SGT"},
{VND_SOURCENEXT, PROD_SOURCENEXT_KEIKAI8,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"SOURCENEXT KeikaiDenwa 8"},
{VND_SOURCENEXT, PROD_SOURCENEXT_KEIKAI8_CHG,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"SOURCENEXT KeikaiDenwa 8 with charger"},
{VND_HAL, PROD_HAL_IMR001,
add_prolific_device, reset_prolific_device,
set_line_coding_acm, set_control_line_state_acm,
on_read_acm, on_write_acm, on_close_acm,
"HAL Corporation Crossam2+USB"},
{VND_FTDI, PROD_8U100AX,
add_ftdi_device, reset_ftdi_device,
set_line_coding_ftdi, set_control_line_state_ftdi,
on_read_ftdi, on_write_ftdi, on_close_ftdi,
"FTDI 8U100AX serial converter"},
{VND_FTDI, PROD_8U232AM,
add_ftdi_device, reset_ftdi_device,
set_line_coding_ftdi, set_control_line_state_ftdi,
on_read_ftdi, on_write_ftdi, on_close_ftdi,
"FTDI 8U232AM serial converter"},
{VND_PALM, PROD_PALM_CONNECT,
add_klsi_device, reset_klsi_device,
set_line_coding_klsi, set_control_line_state_klsi,
on_read_klsi, on_write_klsi, on_close_klsi,
"PalmConnect RS232"},
{VND_KLSI, PROD_KLSI_KL5KUSB105D,
add_klsi_device, reset_klsi_device,
set_line_coding_klsi, set_control_line_state_klsi,
on_read_klsi, on_write_klsi, on_close_klsi,
"KLSI KL5KUSB105D"},
};
/* supported devices*/
usb_support_descriptor *supported_devices;
/* main devices table locking semaphore */
sem_id usb_serial_lock = -1;
/* array of pointers to device objects */
usb_serial_device *usb_serial_devices[DEVICES_COUNT];
/* the names of "ports" */
char * usb_serial_names[DEVICES_COUNT + 1];
/* speed constants, supported by this driver. */
const uint32 serial_tty_speed[] = {
0x00000000, //B0
0x00000032, //B50
0x0000004B, //B75
0x0000006E, //B110
0x00000086, //B134
0x00000096, //B150
0x000000C8, //B200
0x0000012C, //B300
0x00000258, //B600
0x000004B0, //B1200
0x00000708, //B1800
0x00000960, //B2400
0x000012C0, //B4800
0x00002580, //B9600
0x00004B00, //B19200
0x00009600, //B38400
0x0000E100, //B57600
0x0001C200, //B115200
0x00038400, //B230400
0x00070800, //460800
0x000E1000, //921600
};
/* init_hardware - called once the first time the driver is loaded */
status_t init_hardware (void){
TRACE("init_hardware\n"); /*special case - no file-logging activated now*/
return B_OK;
}
/* init_driver - optional function - called every time the driver
is loaded. */
status_t init_driver (void){
int i;
status_t status = B_OK;
load_setting();
create_log();
TRACE_FUNCALLS("init_driver\n");
if((status = get_module(B_TTY_MODULE_NAME, (module_info **)&tty_m)) == B_OK){
if((status = get_module(B_USB_MODULE_NAME, (module_info **)&usb_m)) == B_OK){
if(tty_m && usb_m){
for(i = 0; i < DEVICES_COUNT; i++)
usb_serial_devices[i] = 0;
usb_serial_names[0] = NULL;
load_driver_symbols(DRIVER_NAME);
/* XXX: needs more error checking! */
// build the list of usb supported devices from our own hw list,
// so it's always up to date.
supported_devices = malloc(sizeof(usb_support_descriptor) * SIZEOF(usb_serial_hw_devices));
// ACM devices
supported_devices[0].dev_class = USB_DEV_CLASS_COMM;
supported_devices[0].dev_subclass = 0;
supported_devices[0].dev_protocol = 0;
supported_devices[0].vendor = 0;
supported_devices[0].product = 0;
// other devices
for (i = 1; i < SIZEOF(usb_serial_hw_devices); i++){
supported_devices[i].dev_class = 0;
supported_devices[i].dev_subclass = 0;
supported_devices[i].dev_protocol = 0;
supported_devices[i].vendor = usb_serial_hw_devices[i].vendor_id;
supported_devices[i].product = usb_serial_hw_devices[i].product_id;
}
(*usb_m->register_driver)(DRIVER_NAME, supported_devices,
SIZEOF(usb_serial_hw_devices), DRIVER_NAME);
(*usb_m->install_notify)(DRIVER_NAME, &notify_hooks);
usb_serial_lock = create_sem(1, DRIVER_NAME"_devices_table_lock");
}else{
status = B_ERROR;
TRACE_ALWAYS("init_driver failed: tty_m:%08x usb_m:%08x", tty_m, usb_m);
}
if (status != B_OK)
put_module(B_USB_MODULE_NAME);
}else
TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status,
B_USB_MODULE_NAME);
if (status != B_OK)
put_module(B_TTY_MODULE_NAME);
}else
TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status,
B_TTY_MODULE_NAME);
TRACE_FUNCRET("init_driver returns:%08x\n", status);
return status;
}
/* uninit_driver - optional function - called every time the driver
is unloaded */
void uninit_driver (void){
int i;
TRACE_FUNCALLS("uninit_driver\n");
(*usb_m->uninstall_notify)(DRIVER_NAME);
free(supported_devices);
acquire_sem(usb_serial_lock);
for(i = 0; i < DEVICES_COUNT; i++)
if(usb_serial_devices[i]){
delete_area(usb_serial_devices[i]->buffers_area);
delete_sem(usb_serial_devices[i]->done_read);
delete_sem(usb_serial_devices[i]->done_write);
free(usb_serial_devices[i]);
usb_serial_devices[i] = 0;
}
release_sem_etc(usb_serial_lock, 1, B_DO_NOT_RESCHEDULE);
delete_sem(usb_serial_lock);
for(i = 0; usb_serial_names[i]; i++)
free(usb_serial_names[i]);
put_module(B_USB_MODULE_NAME);
put_module(B_TTY_MODULE_NAME);
}
void usb_serial_device_notify_in(void *cookie,
uint32 status, void *data, uint32 actual_len){
TRACE_FUNCALLS("usb_serial_device_notify_in:cookie:%08x status:%08x data:%08x len:%d\n", cookie, status, data, actual_len);
if(cookie){
usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device;
usd->actual_len_read = actual_len;
usd->dev_status_read = status;
release_sem(usd->done_read);
}
}
void usb_serial_device_notify_out(void *cookie, uint32 status,
void *data, uint32 actual_len){
TRACE_FUNCALLS("usb_serial_device_notify_out:cookie:%08x status:%08x "
"data:%08x len:%d\n", cookie, status, data, actual_len);
if(cookie){
usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device;
usd->actual_len_write = actual_len;
usd->dev_status_write = status;
release_sem(usd->done_write);
}
}
status_t usb_serial_device_thread(void *param){
status_t status = B_ERROR;
usb_serial_device_info *usdi = (usb_serial_device_info *)param;
usb_serial_device *usd = usdi->device;
TRACE_FUNCALLS("usb_serial_device_thread:%08x\n", param);
while(true){
size_t i, to_read;
char *buf;
struct ddrover *ddr;
usd->actual_len_read = 0;
usd->dev_status_read = 0;
status = (*usb_m->queue_bulk)(usd->pipe_read, usd->read_buffer,
usd->read_buffer_size, usb_serial_device_notify_in, usdi);
if(status != B_OK){
TRACE_ALWAYS("usb_serial_device_thread : queue_bulk error : %lx\n", status);
break;
}
status = acquire_sem_etc(usd->done_read, 1, B_CAN_INTERRUPT, 0);
if(status != B_OK){
TRACE_ALWAYS("usb_serial_device_thread : acquire_sem_etc : "
"error %08lx (%s)\n", status, strerror(status));
break;
}
if(usd->dev_status_read){
TRACE_ALWAYS("usb_serial_device_thread : dev_status error !!!\n");
break;
}
buf = usd->read_buffer;
to_read = usd->actual_len_read;
(*usd->hw->on_read)(usd, &buf, &to_read);
if(!to_read)
continue;
ddr = (*tty_m->ddrstart)(NULL);
if(!ddr){
TRACE_ALWAYS("usb_serial_device_thread : ddrstart problem !!!\n");
status = B_NO_MEMORY;
break;
}
(*tty_m->ttyilock)(usd->tty, ddr, true);
for(i = 0; i < to_read; i++){
(*tty_m->ttyin)(usd->tty, ddr, buf[i]);
}
(*tty_m->ttyilock)(usd->tty, ddr, false);
(*tty_m->ddrdone)(ddr);
}
TRACE_FUNCRET("usb_serial_device_thread returns %08x\n", status);
return status;
}
void usb_serial_setmodes(usb_serial_device *usd){
usb_serial_line_coding line_coding;
struct termios tios;
int newctrl, baud_index;
TRACE_FUNCALLS("usb_serial_setmodes:%08x\n", usd);
memcpy(&tios, &usd->tty->t, sizeof(struct termios));
newctrl = usd->ctrlout;
TRACE_FUNCRES(trace_termios, &tios);
TRACE("newctrl:%08x\n", newctrl);
baud_index = tios.c_cflag & CBAUD;
if(baud_index > SIZEOF(serial_tty_speed))
baud_index = SIZEOF(serial_tty_speed) - 1;
line_coding.speed = serial_tty_speed[baud_index];
line_coding.stopbits = ( tios.c_cflag & CSTOPB ) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
if(PARENB & tios.c_cflag){
line_coding.parity = LC_PARITY_EVEN;
if(PARODD & tios.c_cflag){
line_coding.parity = LC_PARITY_ODD;
}
}else
line_coding.parity = LC_PARITY_NONE;
line_coding.databits = (tios.c_cflag & CS8) ? 8 : 7;
if(line_coding.speed == 0){
newctrl &= 0xfffffffe;
line_coding.speed = usd->line_coding.speed;
}else
newctrl = CLS_LINE_DTR;
if(usd->ctrlout != newctrl ){
usd->ctrlout = newctrl;
TRACE("newctrl send to modem:%08x\n", newctrl);
(*usd->hw->set_control_line_state)(usd, newctrl);
}
if(memcmp (&line_coding, &usd->line_coding, sizeof(usb_serial_line_coding))){
usd->line_coding.speed = line_coding.speed;
usd->line_coding.stopbits = line_coding.stopbits;
usd->line_coding.databits = line_coding.databits;
usd->line_coding.parity = line_coding.parity;
TRACE("send to modem:speed %d sb:%08x db:%08x parity:%08x\n",
usd->line_coding.speed, usd->line_coding.stopbits,
usd->line_coding.databits, usd->line_coding.parity);
(*usd->hw->set_line_coding)(usd, &usd->line_coding);
}
}
bool usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags){
int i;
bool bret = false;
usb_serial_device *usd;
TRACE_FUNCALLS("usb_serial_service:%08x ddr:%08x flags:%08x\n", ptty, ddr, flags);
for(i = 0; i < DEVICES_COUNT; i++){
if(usb_serial_devices[i]){
if(ptty == usb_serial_devices[i]->tty){
usd = usb_serial_devices[i];
break;
}
}
}
if(usd){
if(flags <= TTYGETSIGNALS){
switch(flags){
case TTYENABLE:
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, false);
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true);
usd->ctrlout = CLS_LINE_DTR | CLS_LINE_RTS;
(*usd->hw->set_control_line_state)(usd, usd->ctrlout);
break;
case TTYDISABLE:
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, false);
usd->ctrlout = 0x0;
(*usd->hw->set_control_line_state)(usd, usd->ctrlout);
break;
case TTYISTOP:
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, false);
break;
case TTYIRESUME:
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true);
break;
case TTYGETSIGNALS:
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, true);
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true);
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDSR, false);
(*tty_m->ttyhwsignal)(ptty, ddr, TTYHWRI, false);
break;
case TTYSETMODES:
usb_serial_setmodes(usd);
break;
case TTYOSTART:
case TTYOSYNC:
case TTYSETBREAK:
case TTYCLRBREAK:
case TTYSETDTR:
case TTYCLRDTR:
break;
}
}
bret = true;
}
TRACE_FUNCRET("usb_serial_service returns %d\n", bret);
return bret;
}
void usb_serial_notify_interrupt(void *cookie, uint32 status,
void *data, uint32 actual_len){
TRACE_FUNCALLS("usb_serial_notify_interrupt : %p %lx %p %ld\n",
cookie, status, data, actual_len);
if(cookie){
usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device;
usd->actual_len_interrupt = actual_len;
usd->dev_status_interrupt = status;
}
}
/* usb_serial_open - handle open() calls */
static status_t usb_serial_open (const char *name, uint32 flags, void** cookie){
int i;
status_t status = ENODEV;
TRACE_FUNCALLS("usb_serial_open:%s flags:%d cookie:%08x\n",
name, flags, cookie);
for(i=0;i<DEVICES_COUNT;i++)
TRACE("%08x\n",usb_serial_devices[i]);
*cookie = NULL;
i = strtol(name + BASENAME_LEN, NULL, 10);
if(i >= 0 && i < DEVICES_COUNT){
acquire_sem(usb_serial_lock);
if(usb_serial_devices[i]){
usb_serial_device_info *usdi = malloc(sizeof(usb_serial_device_info));
if(usdi){
struct ddrover *ddr;
memset(usdi, 0, sizeof(usb_serial_device_info));
*cookie = usdi;
TRACE("cookie in open:%08x\n", *cookie);
usdi->device = usb_serial_devices[i];
(*tty_m->ttyinit)(&usb_serial_tty[i], true);
usdi->ttyfile.tty = &usb_serial_tty[i];
usdi->ttyfile.flags = flags;
usb_serial_devices[i]->tty = &usb_serial_tty[i];
(*usdi->device->hw->reset_device)(usdi->device);
TRACE("Opened:%s %08x\n", usdi->device->hw->descr, usdi->device->dev);
ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
(*tty_m->ddacquire)(ddr, &usb_serial_dd);
status = (*tty_m->ttyopen)(&usdi->ttyfile, ddr, usb_serial_service);
(*tty_m->ddrdone)(ddr);
if(status == B_OK){
sem_id sem = spawn_kernel_thread(usb_serial_device_thread,
"usb_serial_device_thread", 0xa, usdi);
if(sem != -1)
resume_thread(sem);
else
TRACE_ALWAYS("usb_serial_open: cannot spawn kernel thread!!!\n");
usdi->device->ctrlout = CLS_LINE_DTR | CLS_LINE_RTS;
(*usdi->device->hw->set_control_line_state)(usdi->device,
usdi->device->ctrlout);
status = (*usb_m->queue_interrupt)(usdi->device->pipe_control,
usdi->device->interrupt_buffer,
usdi->device->interrupt_buffer_size,
usb_serial_notify_interrupt, usdi);
}
}else
status = B_NO_MEMORY;
if(status != B_OK)
free(usdi);
}else
status = B_NO_MEMORY;
}
release_sem(usb_serial_lock);
}
TRACE_FUNCRET("usb_serial_open returns:%08x\n", status);
return status;
}
/* usb_serial_read - handle read() calls */
static status_t usb_serial_read (void* cookie, off_t position,
void *buf, size_t* num_bytes){
status_t status = B_OK;
struct ddrover *ddr;
TRACE_FUNCALLS("usb_serial_read:%08x position:%Ld buf:%08x len:%d\n",
cookie, position, buf, *num_bytes);
ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
if(cookie)
status = (*tty_m->ttyread)(cookie, ddr, buf, num_bytes);
else
(*tty_m->ddacquire)(ddr, &usb_serial_dd);
(*tty_m->ddrdone)(ddr);
}else{
TRACE_ALWAYS("usb_serial_read : ddrstart problem !!!\n");
status = B_NO_MEMORY;
}
TRACE_FUNCRET("usb_serial_read returns:%08x readed:%d\n", status, *num_bytes);
return status;
}
/* usb_serial_write - handle write() calls */
static status_t usb_serial_write (void* cookie, off_t position,
const void* buffer, size_t* num_bytes){
status_t status = B_OK;
usb_serial_device_info *usdi = (usb_serial_device_info *)cookie;
usb_serial_device *usd = usdi->device;
size_t to_write = *num_bytes;
TRACE_FUNCALLS("usb_serial_write:%08x position:%Ld buf:%08x len:%d\n",
cookie, position, buffer, *num_bytes);
*num_bytes = 0; /* tell caller nothing was written */
while(to_write > 0){
size_t len = to_write;
(*usd->hw->on_write)(usd, buffer, &len);
usd->actual_len_write = 0;
usd->dev_status_write = 0;
status = (*usb_m->queue_bulk)(usd->pipe_write, usd->write_buffer,
len, usb_serial_device_notify_out, cookie);
if(status != B_OK){
TRACE_ALWAYS("usb_serial_write : dev %p status %lx", cookie, status);
break;
}
status = acquire_sem_etc(usd->done_write, 1, B_CAN_INTERRUPT, 0);
if(status != B_OK){
TRACE_ALWAYS("usb_serial_write : acquire_sem_etc() %lx (%s)",
status, strerror(status));
break;
}
((const char*)buffer) += usd->actual_len_write;
*num_bytes += usd->actual_len_write;
to_write -= usd->actual_len_write;
}
TRACE_FUNCRET("usb_serial_write returns:%08x written:%d\n", status, *num_bytes);
return status;
}
/* usb_serial_control - handle ioctl calls */
static status_t usb_serial_control (void* cookie, uint32 op, void* arg, size_t len){
status_t status = B_BAD_VALUE;
TRACE_FUNCALLS("usb_serial_control cookie:%08x op:%08x arg:%08x len:%d\n",
cookie, op, arg, len);
if(cookie){
struct ddrover *ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
status = (*tty_m->ttycontrol)(cookie, ddr, op, arg, len);
(*tty_m->ddrdone)(ddr);
}else
status = B_NO_MEMORY;
}else
status = ENODEV;
TRACE_FUNCRET("usb_serial_control returns:%08x\n", status);
return status;
}
#if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
/* usb_serial_select - handle select start */
static status_t usb_serial_select (void* cookie, uint8 event, uint32 ref, selectsync *_sync){
status_t status = B_BAD_VALUE;
TRACE_FUNCALLS("usb_serial_select cookie:%08x event:%08x ref:%08x sync:%p\n",
cookie, event, ref, _sync);
if(cookie){
struct ddrover *ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
status = (*tty_m->ttyselect)(cookie, ddr, event, ref, _sync);
(*tty_m->ddrdone)(ddr);
}else
status = B_NO_MEMORY;
}else
status = ENODEV;
TRACE_FUNCRET("usb_serial_select returns:%08x\n", status);
return status;
}
/* usb_serial_deselect - handle select exit */
static status_t usb_serial_deselect (void* cookie, uint8 event, selectsync *_sync){
status_t status = B_BAD_VALUE;
TRACE_FUNCALLS("usb_serial_deselect cookie:%08x event:%08x sync:%p\n",
cookie, event, _sync);
if(cookie){
struct ddrover *ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
status = (*tty_m->ttydeselect)(cookie, ddr, event, _sync);
(*tty_m->ddrdone)(ddr);
}else
status = B_NO_MEMORY;
}else
status = ENODEV;
TRACE_FUNCRET("usb_serial_deselect returns:%08x\n", status);
return status;
}
#endif
/* usb_serial_close - handle close() calls */
static status_t usb_serial_close (void* cookie){
status_t status = ENODEV;
TRACE_FUNCALLS("usb_serial_close:%08x\n", cookie);
if(cookie){
usb_serial_device_info *usdi = (usb_serial_device_info *)cookie;
usb_serial_device *usd = usdi->device;
struct ddrover *ddr;
(*usd->hw->on_close)(usd);
ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
status = (*tty_m->ttyclose)(cookie, ddr);
(*tty_m->ddrdone)(ddr);
}else
status = B_NO_MEMORY;
}
TRACE_FUNCRET("usb_serial_close returns:%08x\n", status);
return status;
}
/* usb_serial_free - called after the last device is closed, and after
all i/o is complete.*/
static status_t usb_serial_free (void* cookie){
status_t status = B_OK;
TRACE_FUNCALLS("usb_serial_free:%08x\n", cookie);
if(cookie){
struct ddrover *ddr = (*tty_m->ddrstart)(NULL);
if(ddr){
status = (*tty_m->ttyfree)(cookie, ddr);
(*tty_m->ddrdone)(ddr);
}else
status = B_NO_MEMORY;
free(cookie);
}
TRACE_FUNCRET("usb_serial_free returns:%08x\n", status);
return status;
}
/* publish_devices - return a null-terminated array of devices
supported by this driver. */
const char** publish_devices(){
int i, j;
TRACE_FUNCALLS("publish_devices\n");
for(i=0; usb_serial_names[i]; i++)
free(usb_serial_names[i]);
acquire_sem(usb_serial_lock);
for(i=0, j=0; i < DEVICES_COUNT; i++){
if(usb_serial_devices[i]){
usb_serial_names[j] = malloc(strlen(basename + 2));
if(usb_serial_names[j]){
sprintf(usb_serial_names[j], basename, i);
j++;
}
else
TRACE_ALWAYS("publish_devices - NO MEMORY\n");
}
}
usb_serial_names[j] = NULL;
release_sem(usb_serial_lock);
return (const char **)&usb_serial_names[0];
}
/* find_device - return ptr to device hooks structure for a
given device name */
device_hooks* find_device(const char* name){
TRACE_FUNCALLS("find_device(%s)\n", name);
return &usb_serial_hooks;
}
status_t add_device(usb_serial_device *usd, const usb_configuration_info *uci,
usb_endpoint_info *comm_epi,
usb_endpoint_info *data_out_epi,
usb_endpoint_info *data_in_epi){
char name[32];
status_t status = ENODEV;
size_t buf_len;
int i = 0;
TRACE_FUNCALLS("add_device(%08x, %08x, %08x, %08x, %08x)\n",
usd, uci, comm_epi, data_in_epi, data_out_epi);
acquire_sem(usb_serial_lock);
for(i = 0; i < DEVICES_COUNT; i++){
if(usb_serial_devices[i] != NULL)
continue;
usb_serial_devices[i] = usd;
usd->active = 1;
usd->open = 0;
sprintf(name, "usb_serial:%d:done_read", i );
usd->done_read = create_sem(0, name);
sprintf(name, "usb_serial:%d:done_write", i);
usd->done_write = create_sem(0, name);
usd->tty = NULL;
buf_len = usd->read_buffer_size + usd->write_buffer_size +
usd->interrupt_buffer_size;
usd->buffers_area = create_area("usb_serial:buffers_area",
(void *)&usd->read_buffer,
B_ANY_KERNEL_ADDRESS,
ROUNDUP(buf_len, B_PAGE_SIZE),
B_CONTIGUOUS, B_READ_AREA|B_WRITE_AREA);
usd->write_buffer = usd->read_buffer + usd->read_buffer_size;
usd->interrupt_buffer = usd->write_buffer + usd->write_buffer_size;
(*usb_m->set_configuration)(usd->dev, uci);
usd->pipe_control = (comm_epi) ? comm_epi->handle : 0;
usd->pipe_write = data_out_epi->handle;
usd->pipe_read = data_in_epi->handle;
status = B_OK;
break;
}
release_sem(usb_serial_lock);
TRACE_FUNCRET("add_device returns:%08x\n", status);
return status;
}
status_t usb_serial_device_added(const usb_device *dev, void **cookie){
int i;
status_t status = B_OK;
const usb_device_descriptor *udd;
usb_serial_device *usd = 0;
TRACE_FUNCALLS("usb_serial_device_added:%08x cookie:%08x\n", dev, cookie);
udd = (*usb_m->get_device_descriptor)(dev);
TRACE_ALWAYS("Probing device: %08x/%08x\n", udd->vendor_id, udd->product_id);
*cookie = 0;
for(i=1; i < sizeof(usb_serial_hw_devices)/sizeof(usb_serial_hw_devices[0]); i++)
if(usb_serial_hw_devices[i].vendor_id == udd->vendor_id
&& usb_serial_hw_devices[i].product_id == udd->product_id){
const usb_configuration_info *uci;
uci = (*usb_m->get_nth_configuration)(dev, 0);
if(uci){
usd = malloc(sizeof(usb_serial_device));
if(usd){
usd->dev = dev;
usd->hw = &usb_serial_hw_devices[i];
usd->read_buffer_size =
usd->write_buffer_size =
usd->interrupt_buffer_size = ROUNDUP(DEF_BUFFER_SIZE, 16);
if((status = (*usb_serial_hw_devices[i].add_device)(usd, uci)) == B_OK){
*cookie = dev;
TRACE_ALWAYS("%s (%04x/%04x) added \n",
usb_serial_hw_devices[i].descr,
usb_serial_hw_devices[i].vendor_id,
usb_serial_hw_devices[i].product_id);
}else
free(usd);
}else
status = B_NO_MEMORY;
}
break;
}
if(!*cookie){
if(b_acm_support &&
udd->device_class == USB_DEV_CLASS_COMM &&
udd->device_subclass == 0 &&
udd->device_protocol == 0 ){
const usb_configuration_info *uci;
uint16 idx = 0;
do{
uci = (*usb_m->get_nth_configuration)(dev, idx++);
if(uci){
if(uci->interface_count != 2)
continue;
usd = malloc(sizeof(usb_serial_device));
if(usd){
usd->dev = dev;
usd->hw = &usb_serial_hw_devices[0];
usd->read_buffer_size =
usd->write_buffer_size =
usd->interrupt_buffer_size = ROUNDUP(DEF_BUFFER_SIZE, 16);
if((status = (*usb_serial_hw_devices[0].add_device)(usd, uci)) == B_OK){
*cookie = dev;
TRACE_ALWAYS("%s (%04x/%04x) added \n",
usb_serial_hw_devices[0].descr,
udd->vendor_id, udd->product_id);
}else
free(usd);
}else
status = B_NO_MEMORY;
}
}while(uci);
}else{
TRACE_ALWAYS("device has wrong class, subclass and protocol\n");
status = B_ERROR;
}
}
TRACE_FUNCRET("usb_serial_device_added returns:%08x\n", status);
return status;
}
status_t usb_serial_device_removed(void *cookie){
int i;
status_t status = B_OK;
usb_device *ud = (usb_device *) cookie;
TRACE_FUNCALLS("usb_serial_device_removed:%08x\n", cookie);
acquire_sem(usb_serial_lock);
for(i = 0; i < DEVICES_COUNT; i++ ){
usb_serial_device *usd = usb_serial_devices[i];
if(usd){
if(ud == usd->dev){
usd->active = 0;
if(!usd->open)
break;
delete_area(usd->buffers_area);
delete_sem(usd->done_read);
delete_sem(usd->done_write);
free(usd);
usb_serial_devices[i] = 0;
}
}
}
release_sem(usb_serial_lock);
TRACE_FUNCRET("usb_serial_device_removed returns:%08x\n", status);
return status;
}

View File

@ -1,161 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_SERIAL_DRIVER_H_
#define _USB_SERIAL_DRIVER_H_
/* The name of this driver ... */
#define DRIVER_NAME "usb_serial"
/* Maximal count of devices supported by this driver at the same time. */
#define DEVICES_COUNT 20
#include "tracing.h"
/* Some usefull helper defines ... */
#define SIZEOF(array) (sizeof(array)/sizeof(array[0])) /* size of array */
/* This one rounds the size to integral count of segs (segments) */
#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1))
/* buffer size */
#define DEF_BUFFER_SIZE 0x100
/* line coding defines ... Come from CDC USB specs? */
#define LC_STOP_BIT_1 0
#define LC_STOP_BIT_2 2
#define LC_PARITY_NONE 0
#define LC_PARITY_ODD 1
#define LC_PARITY_EVEN 2
/* struct that represents line coding */
typedef struct _s_usb_serial_line_coding{
uint32 speed;
uint8 stopbits;
uint8 parity;
uint8 databits;
} usb_serial_line_coding;
/* "forgotten" requests for CDC ACM devices */
#define SET_LINE_CODING 0x20
#define SET_CONTROL_LINE_STATE 0x22
/* control line states */
#define CLS_LINE_DTR 0x0001
#define CLS_LINE_RTS 0x0002
/* "forgotten" attributes etc ...*/
#ifndef USB_EP_ADDR_DIR_IN
#define USB_EP_ADDR_DIR_IN 0x80
#define USB_EP_ADDR_DIR_OUT 0x00
#endif
#ifndef USB_EP_ATTR_CONTROL
#define USB_EP_ATTR_CONTROL 0x00
#define USB_EP_ATTR_ISOCHRONOUS 0x01
#define USB_EP_ATTR_BULK 0x02
#define USB_EP_ATTR_INTERRUPT 0x03
#endif
/* USB class - communication devices */
#define USB_DEV_CLASS_COMM 0x02
#define USB_INT_CLASS_CDC 0x02
#define USB_INT_SUBCLASS_ABSTRACT_CONTROL_MODEL 0x02
#define USB_INT_CLASS_CDC_DATA 0x0a
#define USB_INT_SUBCLASS_DATA 0x00
/* a kind of forward declaration */
typedef struct _s_usb_serial_device usb_serial_device;
/* usb_serial_hw - represents the different hardware devices */
typedef struct _s_usb_serial_hw{
uint16 vendor_id; /* vendor id and card id of device */
uint16 product_id;
/* callbacks used in "customization" of the driver behaviour */
status_t (*add_device)(usb_serial_device *usd,
const usb_configuration_info *uci);
status_t (*reset_device)(usb_serial_device *usd);
status_t (*set_line_coding)(usb_serial_device *usd,
usb_serial_line_coding *line_coding);
status_t (*set_control_line_state)(usb_serial_device *usd, uint16 state);
void (*on_read)(usb_serial_device *usd, char **buf, size_t *num_bytes);
void (*on_write)(usb_serial_device *usd, const char *buf,
size_t *num_bytes);
void (*on_close)(usb_serial_device *usd);
const char *descr; /* informational description */
}usb_serial_hw;
status_t add_device(usb_serial_device *usd, const usb_configuration_info *uci,
usb_endpoint_info *comm_epi,
usb_endpoint_info *data_out_epi,
usb_endpoint_info *data_in_epi);
/* this one was typedefed into usb_serial_device - see above for details
this struct represents the main device object */
struct _s_usb_serial_device{
int active; /* is device active - performing some tasks */
int32 open; /* is device opened */
const usb_device *dev; /* points to usb device handle */
/* communication pipes */
usb_pipe *pipe_control;
usb_pipe *pipe_read;
usb_pipe *pipe_write;
/* line coding */
usb_serial_line_coding line_coding;
/* data buffers */
area_id buffers_area;
/* read buffer */
char *read_buffer;
size_t read_buffer_size;
/* write buffer */
char *write_buffer;
size_t write_buffer_size;
/* interrupt buffer */
char *interrupt_buffer;
size_t interrupt_buffer_size;
/* variables used in callback functionality */
size_t actual_len_read;
uint32 dev_status_read;
size_t actual_len_write;
uint32 dev_status_write;
size_t actual_len_interrupt;
uint32 dev_status_interrupt;
/* semaphores used in callbacks */
sem_id done_read;
sem_id done_write;
uint16 ctrlout;
struct tty *tty;
usb_serial_hw *hw; /* points to corresponding hardware description */
/* place for device specific data */
union{
struct _spec_acm{ /* ACM-compatible devices */
}acm;
struct _spec_prolific{ /* Prolific devices*/
bool is_HX; /* Linux handles HX type differently */
}prolific;
struct _spec_ftdi{ /* FTDI devices*/
uint8 hdrlen;
uint8 status_msr;
uint8 status_lsr;
}ftdi;
struct _spec_klsi{ /* KLSI/PalmConnect */
}klsi;
}spec;
}; /*already typedef-ed - see comment above! */
/* high-level of abstraction of the device*/
typedef struct _s_usb_serial_device_info{
struct ttyfile ttyfile; /* */
usb_serial_device *device; /* */
}usb_serial_device_info;
extern usb_serial_device *usb_serial_devices[];
extern char * usb_serial_names[];
extern usb_module_info *usb_m;
#endif//_USB_SERIAL_DRIVER_H_

View File

@ -1,225 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <USB.h>
#include <string.h>
#include <ttylayer.h>
#include "driver.h"
#include "ftdi.h"
#include "uftdireg.h"
status_t add_ftdi_device(usb_serial_device *usd,
const usb_configuration_info *uci)
{
struct usb_endpoint_info *comm_epi = NULL;
struct usb_endpoint_info *data_out_epi = NULL;
struct usb_endpoint_info *data_in_epi = NULL;
status_t status = ENODEV;
int i = 0;
TRACE_FUNCALLS("> add_ftdi_device(%08x, %08x)\n", usd, uci);
if(uci->interface_count){
struct usb_interface_info *uii = uci->interface[0].active;
for(i = 0; i < uii->endpoint_count; i++){
if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_BULK){
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_IN){
data_in_epi = &uii->endpoint[i];
}else{
if(uii->endpoint[i].descr->endpoint_address
/*USB_EP_ADDR_DIR_OUT = 0x0*/){
comm_epi = data_out_epi = &uii->endpoint[i];
}
}
}
}
if(comm_epi && data_in_epi && data_out_epi){
if(usd->hw->product_id == PROD_8U100AX)
usd->spec.ftdi.hdrlen = 1;
else
usd->spec.ftdi.hdrlen = 0;
usd->read_buffer_size =
usd->write_buffer_size =
usd->interrupt_buffer_size = ROUNDUP(FTDI_BUF_SIZE, 16);
status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi);
}
}
TRACE_FUNCRET("< add_ftdi_device returns:%08x\n", status);
return status;
}
status_t reset_ftdi_device(usb_serial_device *usd){
status_t status = B_OK;
size_t len = 0;
TRACE_FUNCALLS("> reset_ftdi_device(%08x)\n", usd);
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_RESET, FTDI_SIO_RESET_SIO,
FTDI_PIT_DEFAULT, 0, 0, 0, &len);
TRACE_FUNCRET("< reset_ftdi_device returns:%08x\n", status);
return status;
}
status_t set_line_coding_ftdi(usb_serial_device *usd,
usb_serial_line_coding *line_coding){
status_t status = B_OK;
int32 rate, data = 0;
size_t len1 = 0, len2 = 0;
TRACE_FUNCALLS("> set_line_coding_ftdi(%08x, {%d, %02x, %02x, %02x})\n",
usd, line_coding->speed,
line_coding->stopbits,
line_coding->parity,
line_coding->databits);
if(usd->hw->product_id == PROD_8U100AX){
switch (line_coding->speed){
case 300: rate = ftdi_sio_b300; break;
case 600: rate = ftdi_sio_b600; break;
case 1200: rate = ftdi_sio_b1200; break;
case 2400: rate = ftdi_sio_b2400; break;
case 4800: rate = ftdi_sio_b4800; break;
case 9600: rate = ftdi_sio_b9600; break;
case 19200: rate = ftdi_sio_b19200; break;
case 38400: rate = ftdi_sio_b38400; break;
case 57600: rate = ftdi_sio_b57600; break;
case 115200: rate = ftdi_sio_b115200; break;
default:
rate = ftdi_sio_b19200;
TRACE_ALWAYS("= set_line_coding_ftdi: Datarate:%d is not supported "
"by this hardware. Defaulted to %d\n",
line_coding->speed, rate);
break;
}
}else{
switch(line_coding->speed){
case 300: rate = ftdi_8u232am_b300; break;
case 600: rate = ftdi_8u232am_b600; break;
case 1200: rate = ftdi_8u232am_b1200; break;
case 2400: rate = ftdi_8u232am_b2400; break;
case 4800: rate = ftdi_8u232am_b4800; break;
case 9600: rate = ftdi_8u232am_b9600; break;
case 19200: rate = ftdi_8u232am_b19200; break;
case 38400: rate = ftdi_8u232am_b38400; break;
case 57600: rate = ftdi_8u232am_b57600; break;
case 115200: rate = ftdi_8u232am_b115200; break;
case 230400: rate = ftdi_8u232am_b230400; break;
case 460800: rate = ftdi_8u232am_b460800; break;
case 921600: rate = ftdi_8u232am_b921600; break;
default:
rate = ftdi_sio_b19200;
TRACE_ALWAYS("= set_line_coding_ftdi: Datarate:%d is not supported "
"by this hardware. Defaulted to %d\n",
line_coding->speed, rate);
break;
}
}
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_SET_BAUD_RATE, rate,
FTDI_PIT_DEFAULT, 0, 0, 0, &len1);
if(status != B_OK)
TRACE_ALWAYS("= set_line_coding_ftdi: datarate set request failed:%08x",
status);
switch(line_coding->stopbits){
case LC_STOP_BIT_2: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break;
case LC_STOP_BIT_1: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break;
default:
TRACE_ALWAYS("= set_line_coding_ftdi: Wrong stopbits param:%d",
line_coding->stopbits);
break;
}
switch(line_coding->parity){
case LC_PARITY_NONE: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break;
case LC_PARITY_EVEN: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break;
case LC_PARITY_ODD: data |= FTDI_SIO_SET_DATA_PARITY_ODD; break;
default:
TRACE_ALWAYS("= set_line_coding_ftdi: Wrong parity param:%d",
line_coding->parity);
break;
}
switch(line_coding->databits){
case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break;
case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break;
default:
TRACE_ALWAYS("= set_line_coding_ftdi: Wrong databits param:%d",
line_coding->databits);
break;
}
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_SET_DATA, data,
FTDI_PIT_DEFAULT, 0, 0, 0, &len2);
if(status != B_OK)
TRACE_ALWAYS("= set_line_coding_ftdi: data set request failed:%08x",
status);
TRACE_FUNCRET("< set_line_coding_ftdi returns:%08x\n", status);
return status;
}
status_t set_control_line_state_ftdi(usb_serial_device *usd, uint16 state){
status_t status = B_OK;
int32 ctrl;
size_t len = 0;
TRACE_FUNCALLS("> set_control_line_state_ftdi(%08x, %04x)\n", usd, state);
ctrl = (state & CLS_LINE_RTS) ?
FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
ctrl |= (state & CLS_LINE_DTR) ?
FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
FTDI_SIO_MODEM_CTRL, ctrl,
FTDI_PIT_DEFAULT, 0, 0, 0, &len);
if(status != B_OK)
TRACE_ALWAYS("= set_control_line_state_ftdi: control set request "
"failed:%08x", status);
TRACE_FUNCRET("< set_control_line_state_ftdi returns:%08x\n", status);
return status;
}
void on_read_ftdi(usb_serial_device *usd, char **buf, size_t *num_bytes){
usd->spec.ftdi.status_msr = FTDI_GET_MSR(*buf);
usd->spec.ftdi.status_lsr = FTDI_GET_LSR(*buf);
TRACE("MSR:%02x LSR:%02x\n", usd->spec.ftdi.status_msr,
usd->spec.ftdi.status_lsr);
*buf += 2;
*num_bytes -= 2;
}
void on_write_ftdi(usb_serial_device *usd, const char *buf,
size_t *num_bytes){
char *buf_to = usd->write_buffer;
int hdrlen = usd->spec.ftdi.hdrlen;
TRACE("hdrlen:%d\n", hdrlen);
if(*num_bytes > usd->write_buffer_size - hdrlen)
*num_bytes = usd->write_buffer_size - hdrlen;
if(hdrlen > 0)
*buf_to = FTDI_OUT_TAG(*num_bytes, FTDI_PIT_DEFAULT);
memcpy(buf_to + hdrlen, buf, *num_bytes);
*num_bytes += hdrlen;
}
void on_close_ftdi(usb_serial_device *usd){
TRACE_FUNCALLS("> on_close_ftdi(%08x)\n", usd);
(*usb_m->cancel_queued_transfers)(usd->pipe_read);
(*usb_m->cancel_queued_transfers)(usd->pipe_write);
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_FTDI_H_
#define _USB_FTDI_H_
#define VND_FTDI 0x0403
#define PROD_8U100AX 0x8372
#define PROD_8U232AM 0x6001
#define FTDI_BUF_SIZE 0x40
status_t add_ftdi_device(usb_serial_device *usd,
const usb_configuration_info *uci);
status_t reset_ftdi_device(usb_serial_device *usd);
status_t set_line_coding_ftdi(usb_serial_device *usd,
usb_serial_line_coding *line_coding);
status_t set_control_line_state_ftdi(usb_serial_device *usd, uint16 state);
void on_read_ftdi(usb_serial_device *usd, char **buf, size_t *num_bytes);
void on_write_ftdi(usb_serial_device *usd, const char *buf, size_t *num_bytes);
void on_close_ftdi(usb_serial_device *usd);
#endif //_USB_FTDI_H_

View File

@ -0,0 +1,45 @@
#ifndef _KERNEL_CPP_H_
#define _KERNEL_CPP_H_
#include <malloc.h>
inline void *
operator new(size_t size)
{
return malloc(size);
}
inline void *
operator new[](size_t size)
{
return malloc(size);
}
inline void
operator delete(void *pointer)
{
free(pointer);
}
inline void
operator delete[](void *pointer)
{
free(pointer);
}
inline void
terminate(void)
{
}
static inline void
__throw()
{
}
#endif // _KERNEL_CPP_H_

View File

@ -1,173 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <ByteOrder.h>
#include <KernelExport.h>
#include <Drivers.h>
#include <USB.h>
#include <ttylayer.h>
#include "driver.h"
#include "klsi.h"
status_t add_klsi_device(usb_serial_device *usd,
const usb_configuration_info *uci)
{
struct usb_endpoint_info *comm_epi = NULL;
struct usb_endpoint_info *data_out_epi = NULL;
struct usb_endpoint_info *data_in_epi = NULL;
const usb_device_descriptor *ddesc;
status_t status = ENODEV;
uint32 i = 0;
TRACE_FUNCALLS("> add_klsi_device(%08x, %08x)\n", usd, uci);
if(uci->interface_count){
struct usb_interface_info *uii = uci->interface[0].active;
for(i = 0; i < uii->endpoint_count; i++){
if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_INTERRUPT){
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_IN /*USB_EP_ADDR_DIR_OUT = 0x0*/){
TRACE("add_klsi_device:comm endpoint at %d\n", i);
comm_epi = &uii->endpoint[i];
}
}
}
for(i = 0; i < uii->endpoint_count; i++){
if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_BULK){
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_IN){
TRACE("add_klsi_device:in endpoint at %d\n", i);
data_in_epi = &uii->endpoint[i];
// usd->read_buffer_size = uii->endpoint[i].descr->max_packet_size;
}else{
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_OUT){
TRACE("add_klsi_device:out endpoint at %d\n", i);
data_out_epi = &uii->endpoint[i];
// usd->write_buffer_size = uii->endpoint[i].descr->max_packet_size;
}
}
}
}
if(comm_epi && data_in_epi && data_out_epi){
usd->read_buffer_size =
usd->write_buffer_size =
usd->interrupt_buffer_size = ROUNDUP(KLSI_BUF_SIZE, 16);
status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi);
}
}
TRACE_FUNCRET("< add_klsi_device returns:%08x\n", status);
return status;
}
status_t reset_klsi_device(usb_serial_device *usd){
status_t status;
size_t len = 0;
TRACE_FUNCALLS("> reset_klsi_device(%08x)\n", usd);
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT,
KLSI_CONF_REQUEST,
KLSI_CONF_REQUEST_READ_ON, 0, 0,
0, 0, &len);
TRACE_FUNCRET("< reset_klsi_device returns:%08x\n", status);
return status;
}
status_t set_line_coding_klsi(usb_serial_device *usd,
usb_serial_line_coding *line_coding){
status_t status = B_OK;
uint8 rate;
size_t len1 = 0, len2 = 0;
uint8 coding_packet[5];
TRACE_FUNCALLS("> set_line_coding_klsi(%08x, {%d, %02x, %02x, %02x})\n",
usd, line_coding->speed,
line_coding->stopbits,
line_coding->parity,
line_coding->databits);
coding_packet[0] = 5; /* size */
switch (line_coding->speed){
case 300: rate = klsi_sio_b300; break;
case 600: rate = klsi_sio_b600; break;
case 1200: rate = klsi_sio_b1200; break;
case 2400: rate = klsi_sio_b2400; break;
case 4800: rate = klsi_sio_b4800; break;
case 9600: rate = klsi_sio_b9600; break;
case 19200: rate = klsi_sio_b19200; break;
case 38400: rate = klsi_sio_b38400; break;
case 57600: rate = klsi_sio_b57600; break;
case 115200: rate = klsi_sio_b115200; break;
default:
rate = klsi_sio_b19200;
TRACE_ALWAYS("= set_line_coding_klsi: Datarate:%d is not supported "
"by this hardware. Defaulted to %d\n",
line_coding->speed, rate);
break;
}
coding_packet[1] = rate;
/* only 7,8 */
coding_packet[2] = line_coding->databits;
/* unknown */
coding_packet[3] = 0;
coding_packet[4] = 1;
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT,
KLSI_SET_REQUEST, 0, 0, 0,
coding_packet, sizeof(coding_packet), &len1);
if(status != B_OK)
TRACE_ALWAYS("= set_line_coding_ftdi: datarate set request failed:%08x",
status);
return status;
}
status_t set_control_line_state_klsi(usb_serial_device *usd, uint16 state){
status_t status = B_OK;
return status;
}
void on_read_klsi(usb_serial_device *usd, char **buf, size_t *num_bytes){
size_t num;
if (*num_bytes <= 2) {
*num_bytes = 0;
return;
}
num = B_LENDIAN_TO_HOST_INT16(*(uint16*)(*buf));
*num_bytes = MIN(num, (*num_bytes - 2));
*buf += 2;
}
void on_write_klsi(usb_serial_device *usd, const char *buf, size_t *num_bytes){
if(*num_bytes > usd->write_buffer_size)
*num_bytes = usd->write_buffer_size;
if(*num_bytes > 62)
*num_bytes = 62;
*num_bytes = 6;
*((uint16*)usd->write_buffer) = B_HOST_TO_LENDIAN_INT16(*num_bytes);
memcpy(usd->write_buffer+2, buf, *num_bytes);
memcpy(usd->write_buffer+2, "ATDT0\n", 6);
*num_bytes = 64;
}
void on_close_klsi(usb_serial_device *usd){
status_t status;
size_t len = 0;
TRACE_FUNCALLS("> on_close_klsi(%08x)\n", usd);
status = (*usb_m->send_request)(usd->dev,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
KLSI_CONF_REQUEST,
KLSI_CONF_REQUEST_READ_OFF, 0, 0,
0, 0, &len);
(*usb_m->cancel_queued_transfers)(usd->pipe_read);
(*usb_m->cancel_queued_transfers)(usd->pipe_write);
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2003-2004 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_KLSI_H_
#define _USB_KLSI_H_
#define VND_PALM 0x0830
#define VND_KLSI 0x05e9
#define PROD_PALM_CONNECT 0x0080
#define PROD_KLSI_KL5KUSB105D 0x00c0
#define KLSI_SET_REQUEST 0x01
#define KLSI_POLL_REQUEST 0x02
#define KLSI_CONF_REQUEST 0x03
#define KLSI_CONF_REQUEST_READ_ON 0x03
#define KLSI_CONF_REQUEST_READ_OFF 0x02
// not sure
#define KLSI_BUF_SIZE 64
enum {
klsi_sio_b115200 = 0,
klsi_sio_b57600 = 1,
klsi_sio_b38400 = 2,
klsi_sio_b19200 = 4,
klsi_sio_b9600 = 6,
/* unchecked */
klsi_sio_b4800 = 8,
klsi_sio_b2400 = 9,
klsi_sio_b1200 = 10,
klsi_sio_b600 = 11,
klsi_sio_b300 = 12,
};
status_t add_klsi_device(usb_serial_device *usd,
const usb_configuration_info *uci);
status_t reset_klsi_device(usb_serial_device *usd);
status_t set_line_coding_klsi(usb_serial_device *usd,
usb_serial_line_coding *line_coding);
status_t set_control_line_state_klsi(usb_serial_device *usd, uint16 state);
void on_read_klsi(usb_serial_device *usd, char **buf, size_t *num_bytes);
void on_write_klsi(usb_serial_device *usd, const char *buf, size_t *num_bytes);
void on_close_klsi(usb_serial_device *usd);
#endif //_USB_PROLIFIC_H_

View File

@ -1,144 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <USB.h>
#include <ttylayer.h>
#include "driver.h"
#include "prolific.h"
status_t add_prolific_device(usb_serial_device *usd,
const usb_configuration_info *uci)
{
struct usb_endpoint_info *comm_epi = NULL;
struct usb_endpoint_info *data_out_epi = NULL;
struct usb_endpoint_info *data_in_epi = NULL;
const usb_device_descriptor *ddesc;
status_t status = ENODEV;
uint32 i = 0;
TRACE_FUNCALLS("> add_prolific_device(%08x, %08x)\n", usd, uci);
/* check for device type.
* Linux checks for type 0, 1 and HX, but handles 0 and 1 the same.
* We'll just check for HX then.
*/
if ((ddesc = (*usb_m->get_device_descriptor)(usd->dev))){
usd->spec.prolific.is_HX = (ddesc->device_class != 0x02 &&
ddesc->max_packet_size_0 == 0x40);
}
if(uci->interface_count){
struct usb_interface_info *uii = uci->interface[0].active;
for(i = 0; i < uii->endpoint_count; i++){
if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_INTERRUPT){
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_IN /*USB_EP_ADDR_DIR_OUT = 0x0*/){
TRACE("add_prolific_device:comm endpoint at %d\n", i);
comm_epi = &uii->endpoint[i];
}
}
}
/*They say that USB-RSAQ1 has 2 interfaces */
if(uci->interface_count == 2){
uii = uci->interface[1].active;
}
for(i = 0; i < uii->endpoint_count; i++){
if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_BULK){
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_IN){
TRACE("add_prolific_device:in endpoint at %d\n", i);
data_in_epi = &uii->endpoint[i];
}else{
if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
== USB_EP_ADDR_DIR_OUT){
TRACE("add_prolific_device:out endpoint at %d\n", i);
data_out_epi = &uii->endpoint[i];
}
}
}
}
if(comm_epi && data_in_epi && data_out_epi){
usd->read_buffer_size =
usd->write_buffer_size =
usd->interrupt_buffer_size = ROUNDUP(PROLIFIC_BUF_SIZE, 16);
status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi);
}
}
TRACE_FUNCRET("< add_prolific_device returns:%08x\n", status);
return status;
}
struct req_item {
uint8 requestType;
uint8 request;
uint16 value;
uint16 index;
};
#define PLRT_O (USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT)
#define PLRT_I (USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN)
/* Linux sends all those, and it seems to work for me */
/* see drivers/usb/serial/pl2303.c */
static struct req_item pl_reset_common_reqs[] = {
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8484, 0},
{PLRT_O, PROLIFIC_SET_REQUEST, 0x0404, 0},
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8484, 0},
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8383, 0},
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8484, 0},
{PLRT_O, PROLIFIC_SET_REQUEST, 0x0404, 1},
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8484, 0},
{PLRT_I, PROLIFIC_SET_REQUEST, 0x8383, 0},
{PLRT_O, PROLIFIC_SET_REQUEST, 0x0000, 1},
{PLRT_O, PROLIFIC_SET_REQUEST, 0x0001, 0}
};
static struct req_item pl_reset_common_hx[] = {
{PLRT_O, PROLIFIC_SET_REQUEST, 2, 0x44},
{PLRT_O, PROLIFIC_SET_REQUEST, 8, 0},
{PLRT_O, PROLIFIC_SET_REQUEST, 0, 0}
};
static struct req_item pl_reset_common_nhx[] = {
{PLRT_O, PROLIFIC_SET_REQUEST, 2, 0x24}
};
static status_t usb_send_requ_list(const usb_device *dev, struct req_item *list, size_t len){
uint32 i;
status_t status;
for (i = 0; i < len; i++){
char buf[10];
bool o = (list[i].requestType == PLRT_O);
size_t buflen = 1;
status = (*usb_m->send_request)(dev,
list[i].requestType,
list[i].request,
list[i].value,
list[i].index,
0, o?0:buf, o?0:buflen, &buflen);
TRACE("usb_send_requ_list: reqs[%d]: %08lx\n", i, status);
}
return B_OK;
}
status_t reset_prolific_device(usb_serial_device *usd){
status_t status;
TRACE_FUNCALLS("> reset_prolific_device(%08x)\n", usd);
status = usb_send_requ_list(usd->dev, pl_reset_common_reqs, SIZEOF(pl_reset_common_reqs));
if (usd->spec.prolific.is_HX)
status = usb_send_requ_list(usd->dev, pl_reset_common_hx, SIZEOF(pl_reset_common_hx));
else
status = usb_send_requ_list(usd->dev, pl_reset_common_nhx, SIZEOF(pl_reset_common_nhx));
status = B_OK; /* discard */
TRACE_FUNCRET("< reset_prolific_device returns:%08x\n", status);
return status;
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) 2003-2004 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_PROLIFIC_H_
#define _USB_PROLIFIC_H_
#define VND_PROLIFIC 0x067b
#define VND_IODATA 0x04bb
#define VND_ATEN 0x0557
#define VND_TDK 0x04bf
#define VND_RATOC 0x0584
#define VND_ELECOM 0x056e
#define VND_SOURCENEXT 0x0833
#define VND_HAL 0x0b41
#define PROD_IODATA_USBRSAQ 0x0a03
#define PROD_PROLIFIC_RSAQ2 0x04bb
#define PROD_ATEN_UC232A 0x2008
#define PROD_PROLIFIC_PL2303 0x2303
#define PROD_TDK_UHA6400 0x0117
#define PROD_RATOC_REXUSB60 0xb000
#define PROD_ELECOM_UCSGT 0x5003
#define PROD_SOURCENEXT_KEIKAI8 0x039f
#define PROD_SOURCENEXT_KEIKAI8_CHG 0x012e
#define PROD_HAL_IMR001 0x0011
// dobavit?!!!!!!!!!!!!!
// { 0, 0, 0, 0x0eba, 0x1080 }, // ITEGNO
// { 0, 0, 0, 0x0df7, 0x2620 } // MA620
#define PROLIFIC_SET_REQUEST 0x01
#define PROLIFIC_BUF_SIZE 0x100
status_t add_prolific_device(usb_serial_device *usd,
const usb_configuration_info *uci);
status_t reset_prolific_device(usb_serial_device *usd);
#endif //_USB_PROLIFIC_H_

View File

@ -1,169 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#include <Drivers.h>
#include <USB.h>
#include <ttylayer.h>
#include <stdio.h> //sprintf
#include <unistd.h> //posix file i/o - create, write, close
#include <driver_settings.h>
#include "driver.h"
//#include "dano_hack.h"
#if DEBUG
bool b_log = true;
#else
bool b_log = false;
#endif
bool b_log_file = false;
bool b_log_append = false;
bool b_log_funcalls = false;
bool b_log_funcret = false;
bool b_log_funcres = false;
bool b_acm_support = true;
static const char *private_log_path="/boot/home/"DRIVER_NAME".log";
static sem_id loglock;
void load_setting(){
void *settingshandle;
settingshandle = load_driver_settings(DRIVER_NAME);
#if !DEBUG
b_log = get_driver_boolean_parameter(
settingshandle, "debug_output", b_log, true);
#endif
b_log_file = get_driver_boolean_parameter(
settingshandle, "debug_output_in_file", b_log_file, true);
b_log_append = ! get_driver_boolean_parameter(
settingshandle, "debug_output_file_rewrite", !b_log_append, true);
b_log_funcalls = get_driver_boolean_parameter(
settingshandle, "debug_trace_func_calls", b_log_funcalls, false);
b_log_funcret = get_driver_boolean_parameter(
settingshandle, "debug_trace_func_returns", b_log_funcret, false);
b_log_funcres = get_driver_boolean_parameter(
settingshandle, "debug_trace_func_results", b_log_funcres, false);
b_acm_support = get_driver_boolean_parameter(
settingshandle, "support_acm_devices", b_acm_support, true);
unload_driver_settings(settingshandle);
}
void create_log(){
int flags = O_WRONLY | O_CREAT | ((!b_log_append) ? O_TRUNC : 0);
if(!b_log_file)
return;
close(open(private_log_path, flags, 0666));
loglock = create_sem(1, DRIVER_NAME"-logging");
}
void usb_serial_trace(bool b_force, char *fmt, ...){
if(!(b_force || b_log))
return;
{
va_list arg_list;
static char *prefix = "\33[32m"DRIVER_NAME":\33[0m";
static char buf[1024];
char *buf_ptr = buf;
if(!b_log_file){
strcpy(buf, prefix);
buf_ptr += strlen(prefix);
}
va_start(arg_list, fmt);
vsprintf(buf_ptr, fmt, arg_list);
va_end(arg_list);
if(b_log_file){
int fd;
acquire_sem(loglock);
fd = open(private_log_path, O_WRONLY | O_APPEND);
write(fd, buf, strlen(buf));
close(fd);
release_sem(loglock);
}
else
dprintf(buf);
}
}
void trace_ddomain(struct ddomain *dd){
TRACE("struct ddomain\n"
" ddrover: %08x\n"
" bg:%d, locked:%d\n", dd->r, dd->bg, dd->locked);
}
void trace_termios(struct termios *tios){
TRACE("struct termios\n"
" c_iflag:%08x\n"
" c_oflag:%08x\n"
" c_cflag:%08x\n"
" c_lflag:%08x\n"
" c_line: %08x\n"
" c_ixxxxx:%08x\n"
" c_oxxxxx:%08x\n"
" c_cc [%02x, %02x, %02x, %02x, %02x, %02x, "
"%02x, %02x, %02x, %02x, %02x]\n",
tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag,
tios->c_line, tios->c_ixxxxx, tios->c_oxxxxx,
tios->c_cc[0], tios->c_cc[1], tios->c_cc[2], tios->c_cc[3],
tios->c_cc[4], tios->c_cc[5], tios->c_cc[6], tios->c_cc[7],
tios->c_cc[8], tios->c_cc[9], tios->c_cc[10]);
}
void trace_str(struct str *str){
TRACE("struct str\n"
" buffer:%08x\n"
" bufsize:%d\n"
" count:%d\n"
" tail:%d\n"
" allocated: %d\n",
str->buffer,
str->bufsize, str->count, str->tail,
str->allocated);
}
void trace_winsize(struct winsize *ws){
TRACE("struct winsize\n"
" ws_row:%d\n"
" ws_col:%d\n"
" ws_xpixel:%d\n"
" ws_ypixel:%d\n",
ws->ws_row, ws->ws_col, ws->ws_xpixel, ws->ws_ypixel);
}
void trace_tty(struct tty *tty){
TRACE("\n>> STRUCT tty\n"
" nopen:%d, flags:%08x,\n",
tty->nopen, tty->flags);
TRACE("\n ddomain dd:\n");
trace_ddomain(&tty->dd);
TRACE("\n ddomain ddi:\n");
trace_ddomain(&tty->ddi);
TRACE(" pgid: %08x\n", tty->pgid);
TRACE("\n termios t:");
trace_termios(&tty->t);
TRACE(" iactivity: %d, ibusy:%d\n", tty->iactivity, tty->ibusy);
TRACE("\n str istr:\n");
trace_str(&tty->istr);
TRACE("\n str rstr:\n");
trace_str(&tty->rstr);
TRACE("\n str ostr:\n");
trace_str(&tty->ostr);
TRACE("\n winsize wsize:\n");
trace_winsize(&tty->wsize);
TRACE(" service: %08x\n", tty->service);
TRACE("\n<< STRUCT tty\n");
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
* Distributed under the terms of the MIT License.
*
*/
#ifndef _USB_SERIAL_TRACING_H_
#define _USB_SERIAL_TRACING_H_
void load_setting();
void create_log();
void usb_serial_trace(bool b_force, char *fmt, ...);
#define TRACE_ALWAYS(x...) usb_serial_trace(true, x);
#define TRACE(x...) usb_serial_trace(false, x);
extern bool b_log_funcalls;
#define TRACE_FUNCALLS(x...)\
{ if(b_log_funcalls) usb_serial_trace(false, x);}
extern bool b_log_funcret;
#define TRACE_FUNCRET(x...)\
{ if(b_log_funcret) usb_serial_trace(false, x);}
extern bool b_log_funcres;
#define TRACE_FUNCRES(func, param)\
{ if(b_log_funcres) func(param);}
void trace_ddomain(struct ddomain *dd);
void trace_termios(struct termios *tios);
void trace_str(struct str *str);
void trace_winsize(struct winsize *ws);
void trace_tty(struct tty *tty);
extern bool b_acm_support;
#endif//_USB_SERIAL_TRACING_H_

View File

@ -1,37 +1,33 @@
#
# The sample USB serial driver settings file
#
# Rename it to usb_serial and put into
# Rename it to usb_serial and put it into
# /boot/home/config/settings/kernel/drivers/
# After restarting your system the new settings will works.
# After restarting your system the new settings will be applied.
#support_acm_devices - if you have other ACM driver in your system you can disable
# ACM support by setting this key to "false". The default value is "true" - the ACM
# support is activated.
#support_acm_devices true
# Following settings are for debugging purposes.
# The following settings are for debugging purposes.
# Debug output - this is a possibility to view some kind of development related
# information - error and warning messages etc.
# debug_output - activates debug output. The debug builds has debug output
# activated by default and this key has no effect on it. The release builds requires
# to activate this if you want to see debug messages in syslog or in private log file.
# debug_output - activates debug output. The debug builds has debug output
# activated by default and this key has no effect on it. The release builds
# requires to activate this if you want to see debug messages in syslog or in
# private log file.
#
# debug_output true
# debug_output_in_file - activates writing of debug messages into private log file.
# The name of this file is /boot/home/usb_serial.log. If this key is set to true - no messages
# will be written into syslog.
# debug_output_in_file - activates writing of debug messages into private log
# file. The name of this file is /boot/home/usb_serial.log. If this key is set
# to true - no messages will be written into syslog.
#
# debug_output_in_file true
# debug_output_file_rewrite - activates rewriting of private log file on
# calling driver_init() syscall. By default this set in false.
# debug_output_file_rewrite - activates rewriting of private log file on
# calling driver_init() syscall. By default this set in false.
#
# debug_output_file_rewrite false
# debug_trace_func_calls - the information about driver functions calls
# debug_trace_func_calls - the information about driver functions calls
# will be traced. Would you like to see internals? Then activate this.
#
#
# debug_trace_func_calls true