diff --git a/src/add-ons/kernel/drivers/network/Jamfile b/src/add-ons/kernel/drivers/network/Jamfile index aafc022bfb..c42835cc4a 100644 --- a/src/add-ons/kernel/drivers/network/Jamfile +++ b/src/add-ons/kernel/drivers/network/Jamfile @@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network pegasus ; SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8139 ; SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8169 ; SubInclude HAIKU_TOP src add-ons kernel drivers network sis900 ; +SubInclude HAIKU_TOP src add-ons kernel drivers network usb_ecm ; SubInclude HAIKU_TOP src add-ons kernel drivers network via_rhine ; SubInclude HAIKU_TOP src add-ons kernel drivers network vlance ; SubInclude HAIKU_TOP src add-ons kernel drivers network wb840 ; diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/BeOSCompatibility.h b/src/add-ons/kernel/drivers/network/usb_ecm/BeOSCompatibility.h new file mode 100644 index 0000000000..74f5b2af4f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/BeOSCompatibility.h @@ -0,0 +1,59 @@ +/* + Driver for USB Ethernet Control Model devices + Copyright (C) 2008 Michael Lotz + Distributed under the terms of the MIT license. +*/ +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +#ifndef _BEOS_COMPATIBILITY_H_ +#define _BEOS_COMPATIBILITY_H_ + +#include + +#define USB_ENDPOINT_ATTR_CONTROL 0x00 +#define USB_ENDPOINT_ATTR_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_ATTR_BULK 0x02 +#define USB_ENDPOINT_ATTR_INTERRUPT 0x03 +#define USB_ENDPOINT_ATTR_MASK 0x03 + +#define USB_ENDPOINT_ADDR_DIR_IN 0x80 +#define USB_ENDPOINT_ADDR_DIR_OUT 0x00 + +typedef struct mutex { + sem_id sem; + int32 count; +} mutex; + + +static inline void +mutex_init(mutex *lock, const char *name) +{ + lock->sem = create_sem(0, name); + lock->count = 0; +} + + +static inline void +mutex_destroy(mutex *lock) +{ + delete_sem(lock->sem); +} + + +static inline status_t +mutex_lock(mutex *lock) +{ + if (atomic_add(&lock->count, -1) < 0) + return acquire_sem(lock->sem); + return B_OK; +} + + +static inline void +mutex_unlock(mutex *lock) +{ + if (atomic_add(&lock->count, 1) < -1) + release_sem(lock->sem); +} + +#endif /* !HAIKU_TARGET_PLATFORM_HAIKU */ +#endif /* _BEOS_COMPATIBILITY_H_ */ diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/Driver.cpp b/src/add-ons/kernel/drivers/network/usb_ecm/Driver.cpp new file mode 100644 index 0000000000..13f1d5fd46 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/Driver.cpp @@ -0,0 +1,273 @@ +/* + Driver for USB Ethernet Control Model devices + Copyright (C) 2008 Michael Lotz + Distributed under the terms of the MIT license. +*/ +#include +#include +#include + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU +#include // for mutex +#else +#include "BeOSCompatibility.h" // for pseudo mutex +#endif + +#include "Driver.h" +#include "ECMDevice.h" + +static const char *sDeviceBaseName = "net/usb_ecm/"; +ECMDevice *gECMDevices[MAX_DEVICES]; +char *gDeviceNames[MAX_DEVICES + 1]; +usb_module_info *gUSBModule = NULL; +mutex gDriverLock; + + +status_t +usb_ecm_device_added(usb_device device, void **cookie) +{ + *cookie = NULL; + + ECMDevice *ecmDevice = new ECMDevice(device); + status_t status = ecmDevice->InitCheck(); + if (status < B_OK) { + delete ecmDevice; + return status; + } + + mutex_lock(&gDriverLock); + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gECMDevices[i] != NULL) + continue; + + gECMDevices[i] = ecmDevice; + *cookie = ecmDevice; + + TRACE_ALWAYS("ecm device %ld added\n", i); + mutex_unlock(&gDriverLock); + return B_OK; + } + + // no space for the device + delete ecmDevice; + mutex_unlock(&gDriverLock); + return B_ERROR; +} + + +status_t +usb_ecm_device_removed(void *cookie) +{ + mutex_lock(&gDriverLock); + + ECMDevice *device = (ECMDevice *)cookie; + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gECMDevices[i] == device) { + if (device->IsOpen()) { + // the device will be deleted upon being freed + device->Removed(); + } else { + gECMDevices[i] = NULL; + delete device; + } + break; + } + } + + mutex_unlock(&gDriverLock); + return B_OK; +} + + +//#pragma mark - + + +status_t +init_hardware() +{ + TRACE("init_hardware()\n"); + return B_OK; +} + + +status_t +init_driver() +{ + TRACE("init_driver()\n"); + status_t status = get_module(B_USB_MODULE_NAME, + (module_info **)&gUSBModule); + if (status < B_OK) + return status; + + for (int32 i = 0; i < MAX_DEVICES; i++) + gECMDevices[i] = NULL; + + gDeviceNames[0] = NULL; + mutex_init(&gDriverLock, DRIVER_NAME"_devices"); + + static usb_notify_hooks notifyHooks = { + &usb_ecm_device_added, + &usb_ecm_device_removed + }; + + static usb_support_descriptor supportDescriptor = { + USB_INTERFACE_CLASS_CDC, /* CDC - Communication Device Class */ + USB_INTERFACE_SUBCLASS_ECM, /* ECM - Ethernet Control Model */ + 0, 0, 0 /* no protocol, vendor or device */ + }; + + gUSBModule->register_driver(DRIVER_NAME, &supportDescriptor, 1, NULL); + gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); + return B_OK; +} + + +void +uninit_driver() +{ + TRACE("uninit_driver()\n"); + gUSBModule->uninstall_notify(DRIVER_NAME); + mutex_lock(&gDriverLock); + + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gECMDevices[i]) { + delete gECMDevices[i]; + gECMDevices[i] = NULL; + } + } + + for (int32 i = 0; gDeviceNames[i]; i++) { + free(gDeviceNames[i]); + gDeviceNames[i] = NULL; + } + + mutex_destroy(&gDriverLock); + put_module(B_USB_MODULE_NAME); +} + + +static status_t +usb_ecm_open(const char *name, uint32 flags, void **cookie) +{ + TRACE("open(%s, %lu, %p)\n", name, flags, cookie); + mutex_lock(&gDriverLock); + + *cookie = NULL; + status_t status = ENODEV; + int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10); + if (index >= 0 && index < MAX_DEVICES && gECMDevices[index]) { + status = gECMDevices[index]->Open(flags); + *cookie = gECMDevices[index]; + } + + mutex_unlock(&gDriverLock); + return status; +} + + +static status_t +usb_ecm_read(void *cookie, off_t position, void *buffer, size_t *numBytes) +{ + TRACE("read(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); + ECMDevice *device = (ECMDevice *)cookie; + return device->Read((uint8 *)buffer, numBytes); +} + + +static status_t +usb_ecm_write(void *cookie, off_t position, const void *buffer, + size_t *numBytes) +{ + TRACE("write(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); + ECMDevice *device = (ECMDevice *)cookie; + return device->Write((const uint8 *)buffer, numBytes); +} + + +static status_t +usb_ecm_control(void *cookie, uint32 op, void *buffer, size_t length) +{ + TRACE("control(%p, %lu, %p, %lu)\n", cookie, op, buffer, length); + ECMDevice *device = (ECMDevice *)cookie; + return device->Control(op, buffer, length); +} + + +static status_t +usb_ecm_close(void *cookie) +{ + TRACE("close(%p)\n", cookie); + ECMDevice *device = (ECMDevice *)cookie; + return device->Close(); +} + + +static status_t +usb_ecm_free(void *cookie) +{ + TRACE("free(%p)\n", cookie); + ECMDevice *device = (ECMDevice *)cookie; + mutex_lock(&gDriverLock); + status_t status = device->Free(); + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gECMDevices[i] == device) { + // the device is removed already but as it was open the + // removed hook has not deleted the object + gECMDevices[i] = NULL; + delete device; + break; + } + } + + mutex_unlock(&gDriverLock); + return status; +} + + +const char ** +publish_devices() +{ + TRACE("publish_devices()\n"); + for (int32 i = 0; gDeviceNames[i]; i++) { + free(gDeviceNames[i]); + gDeviceNames[i] = NULL; + } + + int32 deviceCount = 0; + mutex_lock(&gDriverLock); + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gECMDevices[i] == NULL) + continue; + + gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4); + if (gDeviceNames[deviceCount]) { + sprintf(gDeviceNames[deviceCount], "%s%ld", sDeviceBaseName, i); + TRACE("publishing %s\n", gDeviceNames[deviceCount]); + deviceCount++; + } else + TRACE_ALWAYS("publish_devices - no memory to allocate device name\n"); + } + + gDeviceNames[deviceCount] = NULL; + mutex_unlock(&gDriverLock); + return (const char **)&gDeviceNames[0]; +} + + +device_hooks * +find_device(const char *name) +{ + TRACE("find_device(%s)\n", name); + static device_hooks deviceHooks = { + usb_ecm_open, + usb_ecm_close, + usb_ecm_free, + usb_ecm_control, + usb_ecm_read, + usb_ecm_write, + NULL, /* select */ + NULL /* deselect */ + }; + + return &deviceHooks; +} diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/Driver.h b/src/add-ons/kernel/drivers/network/usb_ecm/Driver.h new file mode 100644 index 0000000000..bd60c154ab --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/Driver.h @@ -0,0 +1,61 @@ +/* + Driver for USB Ethernet Control Model devices + Copyright (C) 2008 Michael Lotz + Distributed under the terms of the MIT license. +*/ +#ifndef _USB_ECM_DRIVER_H_ +#define _USB_ECM_DRIVER_H_ + +#include +#include +#include +#include + +#include "kernel_cpp.h" + +#define DRIVER_NAME "usb_ecm" +#define MAX_DEVICES 8 + +/* class and subclass codes */ +#define USB_INTERFACE_CLASS_CDC 0x02 +#define USB_INTERFACE_SUBCLASS_ECM 0x06 +#define USB_INTERFACE_CLASS_CDC_DATA 0x0a +#define USB_INTERFACE_SUBCLASS_DATA 0x00 + +/* communication device descriptor subtypes */ +#define FUNCTIONAL_SUBTYPE_UNION 0x06 +#define FUNCTIONAL_SUBTYPE_ETHERNET 0x0f + +typedef struct ethernet_functional_descriptor_s { + uint8 functional_descriptor_subtype; + uint8 mac_address_index; + uint32 ethernet_statistics; + uint16 max_segment_size; + uint16 num_multi_cast_filters; + uint8 num_wakeup_pattern_filters; +} _PACKED ethernet_functional_descriptor; + +extern usb_module_info *gUSBModule; + +extern "C" { +status_t usb_ecm_device_added(usb_device device, void **cookie); +status_t usb_ecm_device_removed(void *cookie); + +status_t init_hardware(); +void uninit_driver(); + +status_t usb_ecm_open(const char *name, uint32 flags, void **cookie); +status_t usb_ecm_read(void *cookie, off_t position, void *buffer, size_t *numBytes); +status_t usb_ecm_write(void *cookie, off_t position, const void *buffer, size_t *numBytes); +status_t usb_ecm_control(void *cookie, uint32 op, void *buffer, size_t length); +status_t usb_ecm_close(void *cookie); +status_t usb_ecm_free(void *cookie); + +const char **publish_devices(); +device_hooks *find_device(const char *name); +} + +#define TRACE(x...) /*dprintf(DRIVER_NAME ": " x)*/ +#define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME ": " x) + +#endif //_USB_ECM_DRIVER_H_ diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.cpp b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.cpp new file mode 100644 index 0000000000..ac2be8ff51 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.cpp @@ -0,0 +1,382 @@ +/* + Driver for USB Ethernet Control Model devices + Copyright (C) 2008 Michael Lotz + Distributed under the terms of the MIT license. +*/ +#include +#include +#include + +#include "BeOSCompatibility.h" +#include "ECMDevice.h" +#include "Driver.h" + +ECMDevice::ECMDevice(usb_device device) + : fStatus(B_ERROR), + fOpen(false), + fRemoved(false), + fDevice(device), + fControlInterfaceIndex(0), + fDataInterfaceIndex(0), + fMACAddressIndex(0), + fMaxSegmentSize(0), + fControlEndpoint(0), + fReadEndpoint(0), + fWriteEndpoint(0) +{ + const usb_device_descriptor *deviceDescriptor + = gUSBModule->get_device_descriptor(device); + const usb_configuration_info *config + = gUSBModule->get_nth_configuration(device, 0); + + if (deviceDescriptor == NULL || config == NULL) { + TRACE_ALWAYS("failed to get basic device info\n"); + return; + } + + TRACE_ALWAYS("creating device: vendor: 0x%04x; device: 0x%04x\n", + deviceDescriptor->vendor_id, deviceDescriptor->product_id); + + uint8 controlIndex = 0; + uint8 dataIndex = 0; + bool foundUnionDescriptor = false; + bool foundEthernetDescriptor = false; + for (size_t i = 0; i < config->interface_count + && (!foundUnionDescriptor || !foundEthernetDescriptor); i++) { + usb_interface_info *interface = config->interface[i].active; + usb_interface_descriptor *descriptor = interface->descr; + if (descriptor->interface_class == USB_INTERFACE_CLASS_CDC + && descriptor->interface_subclass == USB_INTERFACE_SUBCLASS_ECM + && interface->generic_count > 0) { + // try to find and interpret the union and ethernet functional + // descriptors + 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) { + controlIndex = generic->data[1]; + dataIndex = generic->data[2]; + foundUnionDescriptor = true; + } else if (generic->length >= sizeof(ethernet_functional_descriptor) + && generic->data[0] == FUNCTIONAL_SUBTYPE_ETHERNET) { + ethernet_functional_descriptor *ethernet + = (ethernet_functional_descriptor *)generic->data; + fMACAddressIndex = ethernet->mac_address_index; + fMaxSegmentSize = ethernet->max_segment_size; + foundEthernetDescriptor = true; + } + + if (foundUnionDescriptor && foundEthernetDescriptor) + break; + } + } + } + + if (!foundUnionDescriptor) { + TRACE_ALWAYS("did not find a union descriptor\n"); + return; + } + + if (!foundEthernetDescriptor) { + TRACE_ALWAYS("did not find an ethernet descriptor\n"); + return; + } + + if (_ReadMACAddress() != B_OK) { + TRACE_ALWAYS("failed to read mac address\n"); + return; + } + + if (controlIndex >= config->interface_count) { + TRACE_ALWAYS("control interface index invalid\n"); + return; + } + + // check that the indicated control interface fits our needs + usb_interface_info *interface = config->interface[controlIndex].active; + usb_interface_descriptor *descriptor = interface->descr; + if ((descriptor->interface_class != USB_INTERFACE_CLASS_CDC + || descriptor->interface_subclass != USB_INTERFACE_SUBCLASS_ECM) + || interface->endpoint_count == 0) { + TRACE_ALWAYS("control interface invalid\n"); + return; + } + + fControlInterfaceIndex = controlIndex; + fControlEndpoint = interface->endpoint[0].handle; + + if (dataIndex >= config->interface_count) { + TRACE_ALWAYS("data interface index invalid\n"); + return; + } + + // check that the indicated data interface fits our needs + if (config->interface[dataIndex].alt_count < 2) { + TRACE_ALWAYS("data interface does not provide two alternate interfaces\n"); + return; + } + + // alternate 0 is the disabled, endpoint-less default interface + interface = &config->interface[dataIndex].alt[1]; + descriptor = interface->descr; + if (descriptor->interface_class != USB_INTERFACE_CLASS_CDC_DATA + || interface->endpoint_count < 2) { + TRACE_ALWAYS("data interface invalid\n"); + return; + } + + fDataInterfaceIndex = dataIndex; + fNotifyRead = create_sem(0, DRIVER_NAME"_notify_read"); + if (fNotifyRead < B_OK) { + TRACE_ALWAYS("failed to create read notify sem\n"); + return; + } + + fNotifyWrite = create_sem(0, DRIVER_NAME"_notify_write"); + if (fNotifyWrite < B_OK) { + TRACE_ALWAYS("failed to create write notify sem\n"); + delete_sem(fNotifyRead); + return; + } + + fStatus = B_OK; +} + + +ECMDevice::~ECMDevice() +{ + delete_sem(fNotifyRead); + delete_sem(fNotifyWrite); +} + + +status_t +ECMDevice::Open(uint32 flags) +{ + if (fOpen) + return B_BUSY; + + // reset the device by switching the data interface to the disabled first + // interface and then enable it by setting the second actual data interface + const usb_configuration_info *config + = gUSBModule->get_nth_configuration(fDevice, 0); + + gUSBModule->set_alt_interface(fDevice, + &config->interface[fDataInterfaceIndex].alt[0]); + + // update to the changed config + config = gUSBModule->get_nth_configuration(fDevice, 0); + gUSBModule->set_alt_interface(fDevice, + &config->interface[fDataInterfaceIndex].alt[1]); + + // update again + config = gUSBModule->get_nth_configuration(fDevice, 0); + usb_interface_info *interface = config->interface[fDataInterfaceIndex].active; + if (interface->endpoint_count < 2) { + TRACE_ALWAYS("setting the data alternate interface failed\n"); + return B_ERROR; + } + + if (!(interface->endpoint[0].descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)) + fWriteEndpoint = interface->endpoint[0].handle; + else + fReadEndpoint = interface->endpoint[0].handle; + + if (interface->endpoint[1].descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) + fReadEndpoint = interface->endpoint[1].handle; + else + fWriteEndpoint = interface->endpoint[1].handle; + + if (fReadEndpoint == 0 || fWriteEndpoint == 0) { + TRACE_ALWAYS("no read and write endpoints found\n"); + return B_ERROR; + } + + // the device should now be ready + fOpen = true; + return B_OK; +} + + +status_t +ECMDevice::Close() +{ + if (fRemoved) { + fOpen = false; + return B_OK; + } + + gUSBModule->cancel_queued_transfers(fReadEndpoint); + gUSBModule->cancel_queued_transfers(fWriteEndpoint); + + // put the device into non-connected mode again by switching the data + // interface to the disabled alternate + const usb_configuration_info *config + = gUSBModule->get_nth_configuration(fDevice, 0); + + gUSBModule->set_alt_interface(fDevice, + &config->interface[fDataInterfaceIndex].alt[0]); + + fOpen = false; + return B_OK; +} + + +status_t +ECMDevice::Free() +{ + return B_OK; +} + + +status_t +ECMDevice::Read(uint8 *buffer, size_t *numBytes) +{ + if (fRemoved) { + *numBytes = 0; + return B_ERROR; + } + + status_t result = gUSBModule->queue_bulk(fReadEndpoint, buffer, *numBytes, + _ReadCallback, this); + if (result != B_OK) { + *numBytes = 0; + return result; + } + + result = acquire_sem_etc(fNotifyRead, 1, B_CAN_INTERRUPT, 0); + if (result < B_OK) { + *numBytes = 0; + return result; + } + + if (fStatusRead != B_OK) { + TRACE_ALWAYS("device status error 0x%08lx\n", fStatusRead); + result = gUSBModule->clear_feature(fReadEndpoint, + USB_FEATURE_ENDPOINT_HALT); + if (result != B_OK) { + TRACE_ALWAYS("failed to clear halt state\n"); + *numBytes = 0; + return result; + } + } + + *numBytes = fActualLengthRead; + return B_OK; +} + + +status_t +ECMDevice::Write(const uint8 *buffer, size_t *numBytes) +{ + if (fRemoved) { + *numBytes = 0; + return B_ERROR; + } + + status_t result = gUSBModule->queue_bulk(fWriteEndpoint, (uint8 *)buffer, + *numBytes, _WriteCallback, this); + if (result != B_OK) { + *numBytes = 0; + return result; + } + + result = acquire_sem_etc(fNotifyWrite, 1, B_CAN_INTERRUPT, 0); + if (result < B_OK) { + *numBytes = 0; + return result; + } + + if (fStatusWrite != B_OK) { + TRACE_ALWAYS("device status error 0x%08lx\n", fStatusWrite); + result = gUSBModule->clear_feature(fWriteEndpoint, + USB_FEATURE_ENDPOINT_HALT); + if (result != B_OK) { + TRACE_ALWAYS("failed to clear halt state\n"); + *numBytes = 0; + return result; + } + } + + *numBytes = fActualLengthWrite; + return B_OK; +} + + +status_t +ECMDevice::Control(uint32 op, void *buffer, size_t length) +{ + switch (op) { + case ETHER_INIT: + return B_OK; + + case ETHER_GETADDR: + memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); + return B_OK; + + case ETHER_GETFRAMESIZE: + *(uint32 *)buffer = fMaxSegmentSize; + return B_OK; + + default: + TRACE_ALWAYS("unsupported ioctl %lu\n", op); + } + + return B_DEV_INVALID_IOCTL; +} + + +status_t +ECMDevice::_ReadMACAddress() +{ + if (fMACAddressIndex == 0) + return B_BAD_VALUE; + + size_t actualLength = 0; + size_t macStringLength = 26; + uint8 macString[macStringLength]; + status_t result = gUSBModule->get_descriptor(fDevice, USB_DESCRIPTOR_STRING, + fMACAddressIndex, 0, macString, macStringLength, &actualLength); + if (result != B_OK) + return result; + + if (actualLength != macStringLength) { + TRACE_ALWAYS("did not retrieve full mac address\n"); + return B_ERROR; + } + + char macPart[3]; + macPart[2] = 0; + for (int32 i = 0; i < 6; i++) { + macPart[0] = macString[2 + i * 4 + 0]; + macPart[1] = macString[2 + i * 4 + 2]; + fMACAddress[i] = strtol(macPart, NULL, 16); + } + + TRACE_ALWAYS("read mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", + fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], + fMACAddress[4], fMACAddress[5]); + return B_OK; +} + + +void +ECMDevice::_ReadCallback(void *cookie, int32 status, void *data, + uint32 actualLength) +{ + ECMDevice *device = (ECMDevice *)cookie; + device->fActualLengthRead = actualLength; + device->fStatusRead = status; + release_sem_etc(device->fNotifyRead, 1, B_DO_NOT_RESCHEDULE); +} + + +void +ECMDevice::_WriteCallback(void *cookie, int32 status, void *data, + uint32 actualLength) +{ + ECMDevice *device = (ECMDevice *)cookie; + device->fActualLengthWrite = actualLength; + device->fStatusWrite = status; + release_sem_etc(device->fNotifyWrite, 1, B_DO_NOT_RESCHEDULE); +} diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h new file mode 100644 index 0000000000..76a293702f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h @@ -0,0 +1,63 @@ +/* + Driver for USB Ethernet Control Model devices + Copyright (C) 2008 Michael Lotz + Distributed under the terms of the MIT license. +*/ +#ifndef _USB_ECM_DEVICE_H_ +#define _USB_ECM_DEVICE_H_ + +#include "Driver.h" + +class ECMDevice { +public: + ECMDevice(usb_device device); + ~ECMDevice(); + + status_t InitCheck() { return fStatus; }; + + status_t Open(uint32 flags); + bool IsOpen() { return fOpen; }; + + status_t Close(); + status_t Free(); + + status_t Read(uint8 *buffer, size_t *numBytes); + status_t Write(const uint8 *buffer, size_t *numBytes); + status_t Control(uint32 op, void *buffer, size_t length); + + void Removed() { fRemoved = true; }; + bool IsRemoved() { return fRemoved; }; + +private: +static void _ReadCallback(void *cookie, int32 status, + void *data, uint32 actualLength); +static void _WriteCallback(void *cookie, int32 status, + void *data, uint32 actualLength); + + status_t _ReadMACAddress(); + + status_t fStatus; + bool fOpen; + bool fRemoved; + usb_device fDevice; + + uint8 fMACAddress[6]; + + uint8 fControlInterfaceIndex; + uint8 fDataInterfaceIndex; + uint8 fMACAddressIndex; + uint16 fMaxSegmentSize; + + usb_pipe fControlEndpoint; + usb_pipe fReadEndpoint; + usb_pipe fWriteEndpoint; + + uint32 fActualLengthRead; + uint32 fActualLengthWrite; + int32 fStatusRead; + int32 fStatusWrite; + sem_id fNotifyRead; + sem_id fNotifyWrite; +}; + +#endif //_USB_ECM_DEVICE_H_ diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/Jamfile b/src/add-ons/kernel/drivers/network/usb_ecm/Jamfile new file mode 100644 index 0000000000..a23d2201a1 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/Jamfile @@ -0,0 +1,10 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network usb_ecm ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders kernel net ; + +KernelAddon usb_ecm : + Driver.cpp + ECMDevice.cpp + ; diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/kernel_cpp.h b/src/add-ons/kernel/drivers/network/usb_ecm/kernel_cpp.h new file mode 100644 index 0000000000..7d7b025872 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/usb_ecm/kernel_cpp.h @@ -0,0 +1,45 @@ +#ifndef _KERNEL_CPP_H_ +#define _KERNEL_CPP_H_ + +#include + +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_