Skip to content

Instantly share code, notes, and snippets.

@adacosta
Created August 29, 2009 00:27
Show Gist options
  • Save adacosta/177342 to your computer and use it in GitHub Desktop.
Save adacosta/177342 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'ffi'
module USB
extend FFI::Library
ffi_lib '/usr/local/lib/libusb.dylib'
USB_CLASS_PER_INTERFACE = 0
USB_CLASS_AUDIO = 1
USB_CLASS_COMM = 2
USB_CLASS_HID = 3
USB_CLASS_PRINTER = 7
USB_CLASS_PTP = 6
USB_CLASS_MASS_STORAGE = 8
USB_CLASS_HUB = 9
USB_CLASS_DATA = 10
USB_CLASS_VENDOR_SPEC = 0xff
USB_DT_DEVICE = 0x01
USB_DT_CONFIG = 0x02
USB_DT_STRING = 0x03
USB_DT_INTERFACE = 0x04
USB_DT_ENDPOINT = 0x05
USB_DT_HID = 0x21
USB_DT_REPORT = 0x22
USB_DT_PHYSICAL = 0x23
USB_DT_HUB = 0x29
USB_DT_DEVICE_SIZE = 18
USB_DT_CONFIG_SIZE = 9
USB_DT_INTERFACE_SIZE = 9
USB_DT_ENDPOINT_SIZE = 7
USB_DT_ENDPOINT_AUDIO_SIZE = 9
USB_DT_HUB_NONVAR_SIZE = 7
class UsbDescriptorHeader < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8
)
end
class UsbStringDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
# :wData, [:uint16, 1]
:wData, :uint16
)
end
class UsbHidDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
:bcdHID, :uint16,
:bCountryCode, :uint8,
:bNumDescriptors, :uint8
)
end
USB_MAXENDPOINTS = 32
class UsbEndpointDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
:bEndpointAddress, :uint8,
:bmAttributes, :uint8,
:wMaxPacketSize, :uint16,
:bInterval, :uint8,
:bRefresh, :uint8,
:bSynchAddress, :uint8,
:extra, :pointer,
:extralen, :int
)
end
USB_ENDPOINT_ADDRESS_MASK = 0x0f
USB_ENDPOINT_DIR_MASK = 0x80
USB_ENDPOINT_TYPE_MASK = 0x03
USB_ENDPOINT_TYPE_CONTROL = 0
USB_ENDPOINT_TYPE_ISOCHRONOUS = 1
USB_ENDPOINT_TYPE_BULK = 2
USB_ENDPOINT_TYPE_INTERRUPT = 3
USB_MAXINTERFACES = 32
class UsbInterfaceDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
:bInterfaceNumber, :uint8,
:bAlternateSetting, :uint8,
:bNumEndpoints, :uint8,
:bInterfaceClass, :uint8,
:bInterfaceSubClass, :uint8,
:bInterfaceProtocol, :uint8,
:iInterface, :uint8,
:endpoint, :pointer,
:extra, :pointer,
:extralen, :int
)
end
USB_MAXALTSETTING = 128
class UsbInterface < FFI::Struct
layout(
:altsetting, :pointer,
:num_altsetting, :int
)
end
USB_MAXCONFIG = 8
class UsbConfigDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
:wTotalLength, :uint16,
:bNumInterfaces, :uint8,
:bConfigurationValue, :uint8,
:iConfiguration, :uint8,
:bmAttributes, :uint8,
:MaxPower, :uint8,
:interface, :pointer,
:extra, :pointer,
:extralen, :int
)
end
class UsbDeviceDescriptor < FFI::Struct
layout(
:bLength, :uint8,
:bDescriptorType, :uint8,
:bcdUSB, :uint16,
:bDeviceClass, :uint8,
:bDeviceSubClass, :uint8,
:bDeviceProtocol, :uint8,
:bMaxPacketSize0, :uint8,
:idVendor, :uint16,
:idProduct, :uint16,
:bcdDevice, :uint16,
:iManufacturer, :uint8,
:iProduct, :uint8,
:iSerialNumber, :uint8,
:bNumConfigurations, :uint8
)
end
class UsbCtrlSetup < FFI::Struct
layout(
:bRequestType, :uint8,
:bRequest, :uint8,
:wValue, :uint16,
:wIndex, :uint16,
:wLength, :uint16
)
end
USB_REQ_GET_STATUS = 0x00
USB_REQ_CLEAR_FEATURE = 0x01
USB_REQ_SET_FEATURE = 0x03
USB_REQ_SET_ADDRESS = 0x05
USB_REQ_GET_DESCRIPTOR = 0x06
USB_REQ_SET_DESCRIPTOR = 0x07
USB_REQ_GET_CONFIGURATION = 0x08
USB_REQ_SET_CONFIGURATION = 0x09
USB_REQ_GET_INTERFACE = 0x0A
USB_REQ_SET_INTERFACE = 0x0B
USB_REQ_SYNCH_FRAME = 0x0C
USB_TYPE_STANDARD = (0x00 << 5)
USB_TYPE_CLASS = (0x01 << 5)
USB_TYPE_VENDOR = (0x02 << 5)
USB_TYPE_RESERVED = (0x03 << 5)
USB_RECIP_DEVICE = 0x00
USB_RECIP_INTERFACE = 0x01
USB_RECIP_ENDPOINT = 0x02
USB_RECIP_OTHER = 0x03
USB_ENDPOINT_IN = 0x80
USB_ENDPOINT_OUT = 0x00
USB_ERROR_BEGIN = 500000
class UsbDevice < FFI::Struct
layout(
:next, :pointer,
:prev, :pointer,
:filename, :string,
:bus, :pointer,
:descriptor, UsbDeviceDescriptor,
:config, :pointer,
:dev, :pointer,
:devnum, :uint8,
:num_children, :uchar,
:children, :pointer
)
end
class UsbBus < FFI::Struct
layout(
:next, :pointer,
:prev, :pointer,
:dirname, :string,
:devices, :pointer,
:location, :uint32,
:root_dev, :pointer
)
end
attach_function :usb_open, [ :pointer ], :pointer
attach_function :usb_close, [ :pointer ], :int
attach_function :usb_get_string, [ :pointer, :int, :int, :string, :uint ], :int
attach_function :usb_get_string_simple, [ :pointer, :int, :string, :uint ], :int
attach_function :usb_get_descriptor_by_endpoint, [ :pointer, :int, :uchar, :uchar, :pointer, :int ], :int
attach_function :usb_get_descriptor, [ :pointer, :uchar, :uchar, :pointer, :int ], :int
attach_function :usb_bulk_write, [ :pointer, :int, :string, :int, :int ], :int
attach_function :usb_bulk_read, [ :pointer, :int, :string, :int, :int ], :int
attach_function :usb_interrupt_write, [ :pointer, :int, :string, :int, :int ], :int
attach_function :usb_interrupt_read, [ :pointer, :int, :string, :int, :int ], :int
attach_function :usb_control_msg, [ :pointer, :int, :int, :int, :int, :string, :int, :int ], :int
attach_function :usb_set_configuration, [ :pointer, :int ], :int
attach_function :usb_claim_interface, [ :pointer, :int ], :int
attach_function :usb_release_interface, [ :pointer, :int ], :int
attach_function :usb_set_altinterface, [ :pointer, :int ], :int
attach_function :usb_resetep, [ :pointer, :uint ], :int
attach_function :usb_clear_halt, [ :pointer, :uint ], :int
attach_function :usb_reset, [ :pointer ], :int
attach_function :usb_strerror, [ ], :string
attach_function :usb_init, [ ], :void
attach_function :usb_set_debug, [ :int ], :void
attach_function :usb_find_busses, [ ], :int
attach_function :usb_find_devices, [ ], :int
attach_function :usb_device, [ :pointer ], :pointer
attach_function :usb_get_busses, [ ], :pointer
end
u = USB.usb_init
USB.usb_set_debug(1)
USB.usb_find_busses
bus = USB::UsbBus.new(USB::usb_get_busses)
begin
while true do
puts bus.inspect
[:dirname, :location].each {|meth| puts " #{meth} = " + bus[meth].to_s.unpack('H*')[0].inspect}
device = USB::UsbDevice.new(bus[:devices])
begin
while true do
[:filename, :bus, :devnum, :num_children].each do |meth|
begin
puts " #{meth} = " + device[meth].inspect
rescue FFI::NullPointerError
puts " device attribute access failure"
rescue ArgumentError; puts " #{meth.to_s} :" + $!
end
end
device = USB::UsbDevice.new(device[:next])
end
rescue FFI::NullPointerError
puts " End of devices for this bus"
end
bus = USB::UsbBus.new(bus[:next])
end
rescue FFI::NullPointerError
puts "End of busses"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment