diff --git a/headers/os/usb/USBKit.h b/headers/os/usb/USBKit.h new file mode 100644 index 0000000000..a093d9dbf9 --- /dev/null +++ b/headers/os/usb/USBKit.h @@ -0,0 +1,211 @@ + +// USBKit.h +// +// Copyright 1999, Be Incorporated. +// +// Prototype USB Kit / Prerelease Sample Code +// Contents may change massively before official release. + +#ifndef _USBKIT_H +#define _USBKIT_H + +// Provides definitions for usb_xxx_descriptor structures. +#include + +#include + +class USBDevice; +class USBEndpoint; +class USBInterface; +class USBConfiguration; +class USBRosterLooper; + +class USBEndpoint +{ +public: +// Connectivity functions (this endpoint belongs to an Interface that +// belongs to a Configuration that belongs to a Device) + const USBInterface *Interface(void) const; + const USBConfiguration *Configuration(void) const; + const USBDevice *Device(void) const; + +// Raw descriptor data + const usb_endpoint_descriptor *Descriptor(void) const; + +// Descriptor Accessor Functions + bool IsBulk(void) const; + bool IsInterrupt(void) const; + bool IsIsochronous(void) const; + bool IsInput(void) const; + bool IsOutput(void) const; + uint16 MaxPacketSize(void) const; + uint8 Interval(void) const; + +// Initiate a USB Transaction + status_t InterruptTransfer(void *data, size_t length) const; + status_t BulkTransfer(void *data, size_t length) const; + +private: + friend USBDevice; // Only created by a USBDevice + friend USBInterface; // Only destroyed by a containing USBInterface + USBEndpoint(uint32 n, USBInterface *ifc); + ~USBEndpoint(); + + USBInterface *interface; + usb_endpoint_descriptor descriptor; + uint32 endpoint_num; +}; + +class USBInterface +{ +public: +// Connectivity functions (this Interface belongs to a Configuration which +// belongs to a Device) + const USBConfiguration *Configuration(void) const; + const USBDevice *Device(void) const; + +// Iterate over the Endpoints defined by this Interface + uint32 CountEndpoints(void) const; + const USBEndpoint *EndpointAt(uint32 n) const; + +// Access the raw descriptor + const usb_interface_descriptor *Descriptor(void) const; + +// Accessors for useful bits in the descriptor + uint8 Class(void) const; + uint8 Subclass(void) const; + uint8 Protocol(void) const; + const char *InterfaceString(void) const; + +private: + friend USBDevice; // only created by USBDevice + friend USBConfiguration; // only destroyed by the containing Configuration + USBInterface(uint32 n, USBConfiguration *cfc); + ~USBInterface(); + + USBConfiguration *configuration; + usb_interface_descriptor descriptor; + uint32 interface_num; + BList endpoints; +}; + +class USBConfiguration +{ +public: +// Connectivity functions (this Configuration belongs to a Device) + const USBDevice *Device(void) const; + +// Iterators for the Interfaces provided by this Configuration + uint32 CountInterfaces(void) const; + const USBInterface *InterfaceAt(uint32 n) const; + +// Access the raw descriptor + const usb_configuration_descriptor *Descriptor(void) const; + +private: + friend USBDevice; + USBConfiguration(uint n, USBDevice *dev); + ~USBConfiguration(); + + USBDevice *device; + uint configuration_num; + usb_configuration_descriptor descriptor; + BList interfaces; +}; + +class USBDevice +{ +public: + USBDevice(const char *path = NULL); + virtual ~USBDevice(); + virtual status_t InitCheck(void); + status_t SetTo(const char *path); + +// Bus Topology information methods: + +// Return the logical path (eg 0/0/1 of the device), or NULL if unconfigured + const char *Location(void) const; +// Return true if this device is a usb hub + bool IsHub(void) const; + +// Accessors for useful bits in the descriptor + uint16 USBVersion(void) const; + uint8 Class(void) const; + uint8 Subclass(void) const; + uint8 Protocol(void) const; + uint8 MaxEndpoint0PacketSize(void) const; + uint16 VendorID(void) const; + uint16 ProductID(void) const; + uint16 Version(void) const; + const char *ManufacturerString(void) const; + const char *ProductString(void) const; + const char *SerialNumberString(void) const; + +// Access the raw descriptor + const usb_device_descriptor *Descriptor(void) const; + +// Read a string descriptor from the Device into a buffer + size_t GetStringDescriptor(uint32 n, usb_string_descriptor *desc, size_t length) const; + +// Read a string descriptor, convert it from Unicode to UTF8, return a new char[] +// containing the string (must be delete'd by the caller) + char *DecodeStringDescriptor(uint32 n) const; + +// Iterate over the possible configurations + uint32 CountConfigurations(void) const; + const USBConfiguration *ConfigurationAt(uint32 n) const; + +// View and select the active configuration + const USBConfiguration *ActiveConfiguration(void) const; + status_t SetConfiguration(const USBConfiguration *conf); + +// Initiate a Control (endpoint 0) transaction + status_t ControlTransfer(uint8 request_type, uint8 request, uint16 value, + uint16 index, uint16 length, void *data) const; + +private: + status_t InterruptTransfer(const USBEndpoint *e, void *data, size_t length) const; + status_t BulkTransfer(const USBEndpoint *e, void *data, size_t length) const; + + void Release(void); + void PopulateInterface(USBInterface *ifc, usb_interface_descriptor *descr); + void PopulateConfig(USBConfiguration *conf, usb_configuration_descriptor *descr); + void PopulateDevice(void); + + mutable char *serial_string; // Cache the string descriptors + mutable char *manufacturer_string; + mutable char *product_string; + char *location; // Bus Topology info + bool ishub; + int fd; // Connection to /dev/bus/usb/... + usb_device_descriptor descriptor; // Cache the descriptor + USBConfiguration *active; // Current active configuration + BList configurations; // All possible configurations + +friend USBEndpoint; // USBEndpoint uses the XxxTransfer() methods +}; + + +class USBRoster +{ +public: + USBRoster(void); + virtual ~USBRoster(); + +// DeviceAdded() is called when a new device appears on the Bus. +// If the result is not B_OK, the USBDevice instance is deleted and +// there will be no DeviceRemoved notification. + virtual status_t DeviceAdded(USBDevice *dev) = 0; + +// DeviceRemoved() is called when a device is disconnected from the Bus. +// The USBDevice WILL BE deleted after this method returns. + virtual void DeviceRemoved(USBDevice *dev) = 0; + + void Start(void); + void Stop(void); +private: + USBRosterLooper *rlooper; + +}; + +#endif \ No newline at end of file diff --git a/src/kits/usb/USBConfiguration.cpp b/src/kits/usb/USBConfiguration.cpp new file mode 100644 index 0000000000..29b17733dc --- /dev/null +++ b/src/kits/usb/USBConfiguration.cpp @@ -0,0 +1,46 @@ + +#include + +// USBConfiguration ------------------------------------------------------------------ + +uint32 +USBConfiguration::CountInterfaces(void) const +{ + return descriptor.number_interfaces; +} + +const USBInterface * +USBConfiguration::InterfaceAt(uint32 n) const +{ + return (USBInterface *) interfaces.ItemAt(n); +} + +const usb_configuration_descriptor * +USBConfiguration::Descriptor(void) const +{ + return &descriptor; +} + +const USBDevice * +USBConfiguration::Device(void) const +{ + return device; +} + +USBConfiguration::USBConfiguration(uint n, USBDevice *dev) +{ + configuration_num = n; + device = dev; +} + +USBConfiguration::~USBConfiguration() +{ + int i; + USBInterface *ifc; + + for(i=0;(ifc = (USBInterface *) interfaces.ItemAt(i)); i++){ + delete ifc; + } + interfaces.MakeEmpty(); +} + diff --git a/src/kits/usb/USBDevice.cpp b/src/kits/usb/USBDevice.cpp new file mode 100644 index 0000000000..e99bdfa595 --- /dev/null +++ b/src/kits/usb/USBDevice.cpp @@ -0,0 +1,419 @@ + +#include +#include +#include +#include +#include +#include + +// USBDevice ------------------------------------------------------------------------- + +USBDevice::USBDevice(const char *path) +{ + fd = -1; + serial_string = NULL; + manufacturer_string = NULL; + product_string = NULL; + active = NULL; + ishub = false; + location = NULL; + + SetTo(path); +} + +USBDevice::~USBDevice() +{ + Release(); +} + +const char * +USBDevice::Location(void) const +{ + return (const char *) location; +} + +bool +USBDevice::IsHub(void) const +{ + return ishub; +} + +// Release allocated resources (for destructor or reinit) +void USBDevice::Release(void) +{ + int i; + USBConfiguration *cfg; + + ishub = false; + + if(fd != -1) { + close(fd); + fd = -1; + } + + if(location){ + free(location); + location = NULL; + } + + if(serial_string) { + delete[] serial_string; + serial_string = NULL; + } + + if(manufacturer_string) { + delete[] manufacturer_string; + manufacturer_string = NULL; + } + + if(product_string) { + delete[] product_string; + product_string = NULL; + } + + for(i=0;(cfg = (USBConfiguration *) configurations.ItemAt(i)); i++){ + delete cfg; + } + configurations.MakeEmpty(); +} + +void +USBDevice::PopulateInterface(USBInterface *ifc, usb_interface_descriptor *descr) +{ + uint i; + memcpy(&(ifc->descriptor),descr,sizeof(usb_interface_descriptor)); + for(i=0;iCountEndpoints();i++){ + usb_raw_command cmd; + usb_endpoint_descriptor descr; + cmd.endpoint.descr = &descr; + cmd.endpoint.config_num = ifc->configuration->configuration_num; + cmd.endpoint.interface_num = ifc->interface_num; + cmd.endpoint.endpoint_num = i; + ioctl(fd,get_endpoint_descriptor,&cmd,sizeof(cmd)); + if(!cmd.endpoint.status){ + USBEndpoint *ept = new USBEndpoint(i,ifc); + memcpy(&(ept->descriptor),&descr,sizeof(usb_endpoint_descriptor)); + ept->endpoint_num = i; + ifc->endpoints.AddItem(ept); + } + } +} + +void +USBDevice::PopulateConfig(USBConfiguration *conf, usb_configuration_descriptor *descr) +{ + uint i; + memcpy(&(conf->descriptor),descr,sizeof(usb_configuration_descriptor)); + for(i=0;iCountInterfaces();i++){ + usb_raw_command cmd; + usb_interface_descriptor descr; + cmd.interface.descr = &descr; + cmd.interface.config_num = conf->configuration_num; + cmd.interface.interface_num = i; + ioctl(fd,get_interface_descriptor,&cmd,sizeof(cmd)); + if(!cmd.interface.status){ + USBInterface *ifc = new USBInterface(i,conf); + ifc->interface_num = i; + PopulateInterface(ifc,&descr); + conf->interfaces.AddItem(ifc); + } + } +} + +void +USBDevice::PopulateDevice(void) +{ + uint i; + for(i=0;i 255)) return NULL; + l = (l-2)/2; + s = new char[l+1]; + for(i=0;iconfiguration_num; + if(ioctl(fd, set_configuration, &cmd, sizeof(cmd))){ + return B_ERROR; + } else { + if(!cmd.generic.status) active = (USBConfiguration *) conf; + return cmd.generic.status ? B_ERROR : B_OK; + } +} + +status_t +USBDevice::ControlTransfer(uint8 request_type, uint8 request, uint16 value, + uint16 index, uint16 length, void *data) const +{ + usb_raw_command cmd; + cmd.control.request_type = request_type; + cmd.control.request = request; + cmd.control.value = value; + cmd.control.index = index; + cmd.control.length = length; + cmd.control.data = data; + + if(ioctl(fd, do_control, &cmd, sizeof(cmd))){ + return B_ERROR; + } else { + return cmd.generic.status ? B_ERROR : B_OK; + } +} + +status_t +USBDevice::InterruptTransfer(const USBEndpoint *e, void *data, size_t length) const +{ + if(!e || (e->Device() != this)) return B_ERROR; + + usb_raw_command cmd; + cmd.interrupt.interface = e->interface->interface_num; + cmd.interrupt.endpoint = e->endpoint_num; + cmd.interrupt.data = data; + cmd.interrupt.length = length; + + if(ioctl(fd, do_interrupt, &cmd, sizeof(cmd))){ + return B_ERROR; + } else { + return cmd.generic.status ? B_ERROR : B_OK; + } +} + +status_t +USBDevice::BulkTransfer(const USBEndpoint *e, void *data, size_t length) const +{ + if(!e || (e->Device() != this)) return B_ERROR; + + usb_raw_command cmd; + cmd.bulk.interface = e->interface->interface_num; + cmd.bulk.endpoint = e->endpoint_num; + cmd.bulk.data = data; + cmd.bulk.length = length; + + if(ioctl(fd, do_bulk, &cmd, sizeof(cmd))){ + return B_ERROR; + } else { + return cmd.generic.status ? B_ERROR : B_OK; + } +} + diff --git a/src/kits/usb/USBEndpoint.cpp b/src/kits/usb/USBEndpoint.cpp new file mode 100644 index 0000000000..d6d7e3ed34 --- /dev/null +++ b/src/kits/usb/USBEndpoint.cpp @@ -0,0 +1,94 @@ + +// USBEndpoint ------------------------------------------------------------------------ + +#include + +const USBInterface * +USBEndpoint::Interface(void) const +{ + return interface; +} + +const USBConfiguration * +USBEndpoint::Configuration(void) const +{ + return interface->Configuration(); +} + +const USBDevice * +USBEndpoint::Device(void) const +{ + return interface->Configuration()->Device(); +} + +const usb_endpoint_descriptor * +USBEndpoint::Descriptor(void) const +{ + return &descriptor; +} + +bool +USBEndpoint::IsBulk(void) const +{ + return (descriptor.attributes & 0x03) == 0x02; +} + +bool +USBEndpoint::IsInterrupt(void) const +{ + return (descriptor.attributes & 0x03) == 0x03; +} + +bool +USBEndpoint::IsIsochronous(void) const +{ + return (descriptor.attributes & 0x03) == 0x01; +} + +bool +USBEndpoint::IsInput(void) const +{ + return (descriptor.endpoint_address & 0x01) == 0x01; +} + +bool +USBEndpoint::IsOutput(void) const +{ + return (descriptor.endpoint_address & 0x01) == 0x00; +} + +uint16 +USBEndpoint::MaxPacketSize(void) const +{ + return descriptor.max_packet_size; +} + +uint8 +USBEndpoint::Interval(void) const +{ + return descriptor.interval; +} + +status_t +USBEndpoint::InterruptTransfer(void *data, size_t length) const +{ + return Device()->InterruptTransfer(this,data,length); +} + +status_t +USBEndpoint::BulkTransfer(void *data, size_t length) const +{ + return Device()->BulkTransfer(this,data,length); +} + +USBEndpoint::USBEndpoint(uint32 n, USBInterface *ifc) +{ + endpoint_num = n; + interface = ifc; +} + +USBEndpoint::~USBEndpoint() +{ + // nothing to do here really. +} + diff --git a/src/kits/usb/USBInterface.cpp b/src/kits/usb/USBInterface.cpp new file mode 100644 index 0000000000..95e861b525 --- /dev/null +++ b/src/kits/usb/USBInterface.cpp @@ -0,0 +1,75 @@ + +#include + +// USBInterface ---------------------------------------------------------------------- + +uint32 +USBInterface::CountEndpoints(void) const +{ + return descriptor.num_endpoints; +} + +const USBEndpoint * +USBInterface::EndpointAt(uint32 n) const +{ + return (USBEndpoint *) endpoints.ItemAt(n); +} + +const usb_interface_descriptor * +USBInterface::Descriptor(void) const +{ + return &descriptor; +} + +uint8 +USBInterface::Class(void) const +{ + return descriptor.interface_class; +} + +uint8 +USBInterface::Subclass(void) const +{ + return descriptor.interface_subclass; +} + +uint8 +USBInterface::Protocol(void) const +{ + return descriptor.interface_protocol; +} + +const char * +USBInterface::InterfaceString(void) const +{ + return NULL; +} + +const USBConfiguration * +USBInterface::Configuration(void) const +{ + return configuration; +} + +const USBDevice * +USBInterface::Device(void) const +{ + return configuration->Device(); +} + +USBInterface::USBInterface(uint32 n, USBConfiguration *cfg) +{ + interface_num = n; + configuration = cfg; +} + +USBInterface::~USBInterface() +{ + int i; + USBEndpoint *ept; + + for(i=0;(ept = (USBEndpoint *) endpoints.ItemAt(i)); i++){ + delete ept; + } + endpoints.MakeEmpty(); +} diff --git a/src/kits/usb/USBRoster.cpp b/src/kits/usb/USBRoster.cpp new file mode 100644 index 0000000000..17afe6375c --- /dev/null +++ b/src/kits/usb/USBRoster.cpp @@ -0,0 +1,344 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int __directory = 0; +static void *DIRECTORY = (void *) &__directory; + +struct WatchItem +{ + ino_t inode; + + char *name; + void *data; + + WatchItem *children; + WatchItem *next; + WatchItem *parent; + + ~WatchItem(){ + free(name); + } + + char *LongName(void){ + WatchItem *w; + int sz; + char *n; + for(w=parent,sz=1+strlen(name);w;w=w->parent){ + sz += 1+strlen(w->name); + } + n = (char*) malloc(sz); + sz--; + n[sz] = 0; + for(w=this;w;w=w->parent){ + sz -= strlen(w->name); + memcpy(n + sz, w->name, strlen(w->name)); + if(sz){ + sz--; + n[sz]='/'; + } + } + return n; + } + + WatchItem(ino_t inode, const char *name, void *data = NULL){ + parent = NULL; + children = NULL; + next = NULL; + + this->inode = inode; + this->name = strdup(name); + this->data = data; + } + + WatchItem *Find(const char *name0){ + WatchItem *w; + for(w=children;w;w=w->next){ + if(!strcmp(name0,w->name)) return w; + } + return NULL; + } + + WatchItem *Find(ino_t inode0){ + WatchItem *w; + + if(inode == inode0) { + return this; + } + + for(w=children;w;w=w->next){ + WatchItem *r = w->Find(inode0); + if(r) { + return r; + } + } + return NULL; + } + + WatchItem *Remove(WatchItem *w){ + char *n = w->LongName(); + free(n); + + if(w->parent != this) return w; + w->parent = NULL; + + if(children == w){ + children = w->next; + w->next = NULL; + return w; + } + WatchItem *w0; + for(w0=children;w0;w0=w0->next){ + if(w0->next == w){ + w0->next = w->next; + w->next = NULL; + return w; + } + } + return w; + } + + void Add(WatchItem *w){ + w->parent = this; + w->next = children; + children = w; + + char *n = w->LongName(); + free(n); + } +}; + +class USBRosterLooper : public BLooper +{ + friend USBRoster; + + void DestroyItem(WatchItem *item); + void ItemAdded(WatchItem *item); + void WatchDirectory(BEntry &dir, WatchItem *parent); + BMessenger *messenger; + WatchItem *root; + USBRoster *roster; + dev_t dev; + +public: + USBRosterLooper(USBRoster *roster); + virtual void MessageReceived(BMessage *msg); +}; + + +void +USBRosterLooper::WatchDirectory(BEntry &_entry, WatchItem *parent) +{ + node_ref nref; + BEntry entry; + BDirectory dir(&_entry); + if(dir.GetNodeRef(&nref)) return; // Not a directory + BPath path(&_entry); + WatchItem *item; + +// fprintf(stderr,"Watching %s\n",path.Path()); + + item = parent ? parent->Find(nref.node) : NULL; + if(!item) { + item = new WatchItem(nref.node,path.Leaf(), DIRECTORY); + watch_node(&nref, B_WATCH_DIRECTORY, *messenger); + } + + if(!parent){ +// fprintf(stderr,"create root\n"); + parent = root = item; + } else { + parent->Add(item); + } + + + while(dir.GetNextEntry(&entry) == B_NO_ERROR){ + BPath path(&entry); + if(entry.IsDirectory()){ + WatchDirectory(entry, item); + } else { + if(!strcmp(path.Leaf(),"unload")) continue; +// fprintf(stderr,"File %s\n",path.Path()); + if(!item->Find(path.Leaf())){ + struct stat s; + if(!entry.GetStat(&s)){ + USBDevice *dev = new USBDevice(path.Path()); + if(dev->InitCheck() == B_OK){ + WatchItem *wi = new WatchItem(s.st_ino,path.Leaf(),dev); + item->Add(wi); + ItemAdded(wi); + } else { + delete dev; + item->Add(new WatchItem(s.st_ino,path.Leaf())); + } + } + } + } + } +} + +void +USBRosterLooper::MessageReceived(BMessage *msg) +{ + int32 opcode; + if (msg->FindInt32("opcode", &opcode) != B_NO_ERROR) return; + + switch(opcode){ + case B_ENTRY_CREATED: { + ino_t dir; + dev_t device; + const char *name; + if (msg->FindInt32("device", &device) != B_NO_ERROR || + msg->FindInt64("directory", &dir) != B_NO_ERROR || + msg->FindString("name", &name) != B_NO_ERROR) break; + + if(!strcmp(name,"unload")) break; + +// fprintf(stderr,"created - %s (in %Ld)\n",name,dir); + // Locate the directory by its inode + WatchItem *item = root->Find(dir); + if(item){ + // Item already exists? + if(!item->Find(name)){ + entry_ref entryRef(device, dir, name); + BEntry entry(&entryRef); + if(entry.IsDirectory()){ + WatchDirectory(entry,item); + } else { + struct stat s; + entry.GetStat(&s); + BPath path(&entry); + USBDevice *dev = new USBDevice(path.Path()); + if(dev->InitCheck() == B_OK){ + WatchItem *wi = new WatchItem(s.st_ino,name,dev); + item->Add(wi); + ItemAdded(wi); + } else { + delete dev; + item->Add(new WatchItem(s.st_ino,name)); + } + } + } else { + fprintf(stderr,"no item\n"); + } + } + break; + } + + case B_ENTRY_REMOVED: { + ino_t dir; + dev_t device; + ino_t node; + if (msg->FindInt32("device", &device) != B_NO_ERROR || + msg->FindInt64("directory", &dir) != B_NO_ERROR || + msg->FindInt64("node", &node) != B_NO_ERROR) break; +// fprintf(stderr,"removed - %Ld (in %Ld)\n",node,dir); + + // Locate the item by its inode + WatchItem *item = root->Find(node); + if(item && item->parent){ + DestroyItem(item->parent->Remove(item)); + } else { + fprintf(stderr,"no item\n"); + } + } + } +} + +void +USBRosterLooper::DestroyItem(WatchItem *item) +{ + if(!item) return; + if(item->data) { + if(item->data == DIRECTORY){ + node_ref nref; + nref.device = dev; + nref.node = item->inode; + watch_node(&nref, B_STOP_WATCHING, *messenger); + } else { + roster->DeviceRemoved((USBDevice *)item->data); + delete ((USBDevice *)item->data); + } + } + if(item->children){ + WatchItem *w = item->children; + while(w) { + WatchItem *next = w->next; + DestroyItem(w); + w = next; + } + } + delete item; +} + +void +USBRosterLooper::ItemAdded(WatchItem *item) +{ + if(!item) return; + if(item->data && (item->data != DIRECTORY)){ + if(roster->DeviceAdded((USBDevice *)item->data) != B_OK){ + delete ((USBDevice *) item->data); + item->data = NULL; + } + } +} + +USBRosterLooper::USBRosterLooper(USBRoster *r) +{ + BEntry path("/dev/bus/usb"); + if(path.InitCheck()) fprintf(stderr,"BLAGHR!"); + + roster = r; + node_ref nref; + path.GetNodeRef(&nref); + dev = nref.device; + + Run(); + messenger = new BMessenger(this); + Lock(); + WatchDirectory(path,NULL); + Unlock(); +} + + +void +USBRoster::Start(void) +{ + if(!rlooper){ + rlooper = new USBRosterLooper(this); + } +} + +void +USBRoster::Stop(void) +{ + if(rlooper){ + rlooper->Lock(); + rlooper->DestroyItem(rlooper->root); + rlooper->Quit(); + rlooper = NULL; + } +} + +USBRoster::USBRoster(void) +{ + rlooper = NULL; +} + +USBRoster::~USBRoster() +{ + Stop(); +} + +