1*a69892caSSiarzhuk Zharski /* 2*a69892caSSiarzhuk Zharski * Driver for USB Audio Device Class devices. 3*a69892caSSiarzhuk Zharski * Copyright (c) 2009-13 S.Zharski <imker@gmx.li> 4*a69892caSSiarzhuk Zharski * Distributed under the terms of the MIT license. 5*a69892caSSiarzhuk Zharski * 6*a69892caSSiarzhuk Zharski */ 7*a69892caSSiarzhuk Zharski 8*a69892caSSiarzhuk Zharski #include "Driver.h" 9*a69892caSSiarzhuk Zharski 10*a69892caSSiarzhuk Zharski #include <AutoLock.h> 11*a69892caSSiarzhuk Zharski #include <usb/USB_audio.h> 12*a69892caSSiarzhuk Zharski 13*a69892caSSiarzhuk Zharski #include "Device.h" 14*a69892caSSiarzhuk Zharski #include "Settings.h" 15*a69892caSSiarzhuk Zharski 16*a69892caSSiarzhuk Zharski 17*a69892caSSiarzhuk Zharski static const char* sDeviceBaseName = "audio/hmulti/USB Audio/"; 18*a69892caSSiarzhuk Zharski 19*a69892caSSiarzhuk Zharski usb_module_info* gUSBModule = NULL; 20*a69892caSSiarzhuk Zharski 21*a69892caSSiarzhuk Zharski Device* gDevices[MAX_DEVICES]; 22*a69892caSSiarzhuk Zharski char* gDeviceNames[MAX_DEVICES + 1]; 23*a69892caSSiarzhuk Zharski 24*a69892caSSiarzhuk Zharski mutex gDriverLock; 25*a69892caSSiarzhuk Zharski int32 api_version = B_CUR_DRIVER_API_VERSION; 26*a69892caSSiarzhuk Zharski 27*a69892caSSiarzhuk Zharski 28*a69892caSSiarzhuk Zharski status_t 29*a69892caSSiarzhuk Zharski usb_audio_device_added(usb_device device, void** cookie) 30*a69892caSSiarzhuk Zharski { 31*a69892caSSiarzhuk Zharski *cookie = NULL; 32*a69892caSSiarzhuk Zharski 33*a69892caSSiarzhuk Zharski MutexLocker driverLock; 34*a69892caSSiarzhuk Zharski 35*a69892caSSiarzhuk Zharski // check if this is a replug of an existing device first 36*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 37*a69892caSSiarzhuk Zharski if (gDevices[i] == NULL) 38*a69892caSSiarzhuk Zharski continue; 39*a69892caSSiarzhuk Zharski 40*a69892caSSiarzhuk Zharski if (gDevices[i]->CompareAndReattach(device) != B_OK) 41*a69892caSSiarzhuk Zharski continue; 42*a69892caSSiarzhuk Zharski 43*a69892caSSiarzhuk Zharski TRACE(INF, "The device is plugged back. Use entry at %ld.\n", i); 44*a69892caSSiarzhuk Zharski *cookie = gDevices[i]; 45*a69892caSSiarzhuk Zharski return B_OK; 46*a69892caSSiarzhuk Zharski } 47*a69892caSSiarzhuk Zharski 48*a69892caSSiarzhuk Zharski // no such device yet, create a new one 49*a69892caSSiarzhuk Zharski Device* audioDevice = new(std::nothrow) Device(device); 50*a69892caSSiarzhuk Zharski if (audioDevice == 0) 51*a69892caSSiarzhuk Zharski return ENODEV; 52*a69892caSSiarzhuk Zharski 53*a69892caSSiarzhuk Zharski status_t status = audioDevice->InitCheck(); 54*a69892caSSiarzhuk Zharski if (status < B_OK) { 55*a69892caSSiarzhuk Zharski delete audioDevice; 56*a69892caSSiarzhuk Zharski return status; 57*a69892caSSiarzhuk Zharski } 58*a69892caSSiarzhuk Zharski 59*a69892caSSiarzhuk Zharski status = audioDevice->SetupDevice(false); 60*a69892caSSiarzhuk Zharski if (status < B_OK) { 61*a69892caSSiarzhuk Zharski delete audioDevice; 62*a69892caSSiarzhuk Zharski return status; 63*a69892caSSiarzhuk Zharski } 64*a69892caSSiarzhuk Zharski 65*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 66*a69892caSSiarzhuk Zharski if (gDevices[i] != NULL) 67*a69892caSSiarzhuk Zharski continue; 68*a69892caSSiarzhuk Zharski 69*a69892caSSiarzhuk Zharski gDevices[i] = audioDevice; 70*a69892caSSiarzhuk Zharski *cookie = audioDevice; 71*a69892caSSiarzhuk Zharski 72*a69892caSSiarzhuk Zharski TRACE(INF, "New device is added at %ld.\n", i); 73*a69892caSSiarzhuk Zharski return B_OK; 74*a69892caSSiarzhuk Zharski } 75*a69892caSSiarzhuk Zharski 76*a69892caSSiarzhuk Zharski // no space for the device 77*a69892caSSiarzhuk Zharski TRACE(ERR, "Error: no more device entries availble.\n"); 78*a69892caSSiarzhuk Zharski 79*a69892caSSiarzhuk Zharski delete audioDevice; 80*a69892caSSiarzhuk Zharski return B_ERROR; 81*a69892caSSiarzhuk Zharski } 82*a69892caSSiarzhuk Zharski 83*a69892caSSiarzhuk Zharski 84*a69892caSSiarzhuk Zharski status_t 85*a69892caSSiarzhuk Zharski usb_audio_device_removed(void* cookie) 86*a69892caSSiarzhuk Zharski { 87*a69892caSSiarzhuk Zharski MutexLocker driverLock; 88*a69892caSSiarzhuk Zharski 89*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 90*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 91*a69892caSSiarzhuk Zharski if (gDevices[i] == device) { 92*a69892caSSiarzhuk Zharski if (device->IsOpen()) { 93*a69892caSSiarzhuk Zharski // the device will be deleted upon being freed 94*a69892caSSiarzhuk Zharski device->Removed(); 95*a69892caSSiarzhuk Zharski } else { 96*a69892caSSiarzhuk Zharski gDevices[i] = NULL; 97*a69892caSSiarzhuk Zharski delete device; 98*a69892caSSiarzhuk Zharski TRACE(INF, "Device at %ld deleted.\n", i); 99*a69892caSSiarzhuk Zharski } 100*a69892caSSiarzhuk Zharski break; 101*a69892caSSiarzhuk Zharski } 102*a69892caSSiarzhuk Zharski } 103*a69892caSSiarzhuk Zharski 104*a69892caSSiarzhuk Zharski return B_OK; 105*a69892caSSiarzhuk Zharski } 106*a69892caSSiarzhuk Zharski 107*a69892caSSiarzhuk Zharski 108*a69892caSSiarzhuk Zharski status_t 109*a69892caSSiarzhuk Zharski init_hardware() 110*a69892caSSiarzhuk Zharski { 111*a69892caSSiarzhuk Zharski return B_OK; 112*a69892caSSiarzhuk Zharski } 113*a69892caSSiarzhuk Zharski 114*a69892caSSiarzhuk Zharski 115*a69892caSSiarzhuk Zharski status_t 116*a69892caSSiarzhuk Zharski init_driver() 117*a69892caSSiarzhuk Zharski { 118*a69892caSSiarzhuk Zharski status_t status = get_module(B_USB_MODULE_NAME, 119*a69892caSSiarzhuk Zharski (module_info**)&gUSBModule); 120*a69892caSSiarzhuk Zharski if (status < B_OK) 121*a69892caSSiarzhuk Zharski return status; 122*a69892caSSiarzhuk Zharski 123*a69892caSSiarzhuk Zharski load_settings(); 124*a69892caSSiarzhuk Zharski 125*a69892caSSiarzhuk Zharski TRACE(ERR, "%s\n", kVersion); // TODO: always??? 126*a69892caSSiarzhuk Zharski 127*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) 128*a69892caSSiarzhuk Zharski gDevices[i] = NULL; 129*a69892caSSiarzhuk Zharski 130*a69892caSSiarzhuk Zharski gDeviceNames[0] = NULL; 131*a69892caSSiarzhuk Zharski mutex_init(&gDriverLock, DRIVER_NAME"_devices"); 132*a69892caSSiarzhuk Zharski 133*a69892caSSiarzhuk Zharski static usb_notify_hooks notifyHooks = { 134*a69892caSSiarzhuk Zharski &usb_audio_device_added, 135*a69892caSSiarzhuk Zharski &usb_audio_device_removed 136*a69892caSSiarzhuk Zharski }; 137*a69892caSSiarzhuk Zharski 138*a69892caSSiarzhuk Zharski static usb_support_descriptor supportedDevices[] = { 139*a69892caSSiarzhuk Zharski { USB_AUDIO_INTERFACE_AUDIO_CLASS, 0, 0, 0, 0 } 140*a69892caSSiarzhuk Zharski }; 141*a69892caSSiarzhuk Zharski 142*a69892caSSiarzhuk Zharski gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 0, NULL); 143*a69892caSSiarzhuk Zharski gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 144*a69892caSSiarzhuk Zharski return B_OK; 145*a69892caSSiarzhuk Zharski } 146*a69892caSSiarzhuk Zharski 147*a69892caSSiarzhuk Zharski 148*a69892caSSiarzhuk Zharski void 149*a69892caSSiarzhuk Zharski uninit_driver() 150*a69892caSSiarzhuk Zharski { 151*a69892caSSiarzhuk Zharski gUSBModule->uninstall_notify(DRIVER_NAME); 152*a69892caSSiarzhuk Zharski mutex_lock(&gDriverLock); 153*a69892caSSiarzhuk Zharski 154*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 155*a69892caSSiarzhuk Zharski if (gDevices[i]) { 156*a69892caSSiarzhuk Zharski delete gDevices[i]; 157*a69892caSSiarzhuk Zharski gDevices[i] = NULL; 158*a69892caSSiarzhuk Zharski } 159*a69892caSSiarzhuk Zharski } 160*a69892caSSiarzhuk Zharski 161*a69892caSSiarzhuk Zharski for (int32 i = 0; gDeviceNames[i]; i++) { 162*a69892caSSiarzhuk Zharski free(gDeviceNames[i]); 163*a69892caSSiarzhuk Zharski gDeviceNames[i] = NULL; 164*a69892caSSiarzhuk Zharski } 165*a69892caSSiarzhuk Zharski 166*a69892caSSiarzhuk Zharski mutex_destroy(&gDriverLock); 167*a69892caSSiarzhuk Zharski put_module(B_USB_MODULE_NAME); 168*a69892caSSiarzhuk Zharski 169*a69892caSSiarzhuk Zharski release_settings(); 170*a69892caSSiarzhuk Zharski } 171*a69892caSSiarzhuk Zharski 172*a69892caSSiarzhuk Zharski 173*a69892caSSiarzhuk Zharski static status_t 174*a69892caSSiarzhuk Zharski usb_audio_open(const char* name, uint32 flags, void** cookie) 175*a69892caSSiarzhuk Zharski { 176*a69892caSSiarzhuk Zharski MutexLocker driverLock; 177*a69892caSSiarzhuk Zharski 178*a69892caSSiarzhuk Zharski *cookie = NULL; 179*a69892caSSiarzhuk Zharski status_t status = ENODEV; 180*a69892caSSiarzhuk Zharski int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10) - 1; 181*a69892caSSiarzhuk Zharski if (index >= 0 && index < MAX_DEVICES && gDevices[index]) { 182*a69892caSSiarzhuk Zharski status = gDevices[index]->Open(flags); 183*a69892caSSiarzhuk Zharski *cookie = gDevices[index]; 184*a69892caSSiarzhuk Zharski } 185*a69892caSSiarzhuk Zharski 186*a69892caSSiarzhuk Zharski return status; 187*a69892caSSiarzhuk Zharski } 188*a69892caSSiarzhuk Zharski 189*a69892caSSiarzhuk Zharski 190*a69892caSSiarzhuk Zharski static status_t 191*a69892caSSiarzhuk Zharski usb_audio_read(void* cookie, off_t position, void* buffer, size_t* numBytes) 192*a69892caSSiarzhuk Zharski { 193*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 194*a69892caSSiarzhuk Zharski return device->Read((uint8*)buffer, numBytes); 195*a69892caSSiarzhuk Zharski } 196*a69892caSSiarzhuk Zharski 197*a69892caSSiarzhuk Zharski 198*a69892caSSiarzhuk Zharski static status_t 199*a69892caSSiarzhuk Zharski usb_audio_write(void* cookie, off_t position, const void* buffer, 200*a69892caSSiarzhuk Zharski size_t* numBytes) 201*a69892caSSiarzhuk Zharski { 202*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 203*a69892caSSiarzhuk Zharski return device->Write((const uint8*)buffer, numBytes); 204*a69892caSSiarzhuk Zharski } 205*a69892caSSiarzhuk Zharski 206*a69892caSSiarzhuk Zharski 207*a69892caSSiarzhuk Zharski static status_t 208*a69892caSSiarzhuk Zharski usb_audio_control(void* cookie, uint32 op, void* buffer, size_t length) 209*a69892caSSiarzhuk Zharski { 210*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 211*a69892caSSiarzhuk Zharski return device->Control(op, buffer, length); 212*a69892caSSiarzhuk Zharski } 213*a69892caSSiarzhuk Zharski 214*a69892caSSiarzhuk Zharski 215*a69892caSSiarzhuk Zharski static status_t 216*a69892caSSiarzhuk Zharski usb_audio_close(void* cookie) 217*a69892caSSiarzhuk Zharski { 218*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 219*a69892caSSiarzhuk Zharski return device->Close(); 220*a69892caSSiarzhuk Zharski } 221*a69892caSSiarzhuk Zharski 222*a69892caSSiarzhuk Zharski 223*a69892caSSiarzhuk Zharski static status_t 224*a69892caSSiarzhuk Zharski usb_audio_free(void* cookie) 225*a69892caSSiarzhuk Zharski { 226*a69892caSSiarzhuk Zharski Device* device = (Device*)cookie; 227*a69892caSSiarzhuk Zharski 228*a69892caSSiarzhuk Zharski MutexLocker driverLock; 229*a69892caSSiarzhuk Zharski 230*a69892caSSiarzhuk Zharski status_t status = device->Free(); 231*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 232*a69892caSSiarzhuk Zharski if (gDevices[i] == device) { 233*a69892caSSiarzhuk Zharski // the device is removed already but as it was open the 234*a69892caSSiarzhuk Zharski // removed hook has not deleted the object 235*a69892caSSiarzhuk Zharski gDevices[i] = NULL; 236*a69892caSSiarzhuk Zharski delete device; 237*a69892caSSiarzhuk Zharski TRACE(INF, "Device at %ld deleted.\n", i); 238*a69892caSSiarzhuk Zharski break; 239*a69892caSSiarzhuk Zharski } 240*a69892caSSiarzhuk Zharski } 241*a69892caSSiarzhuk Zharski 242*a69892caSSiarzhuk Zharski return status; 243*a69892caSSiarzhuk Zharski } 244*a69892caSSiarzhuk Zharski 245*a69892caSSiarzhuk Zharski 246*a69892caSSiarzhuk Zharski const char** 247*a69892caSSiarzhuk Zharski publish_devices() 248*a69892caSSiarzhuk Zharski { 249*a69892caSSiarzhuk Zharski for (int32 i = 0; gDeviceNames[i]; i++) { 250*a69892caSSiarzhuk Zharski free(gDeviceNames[i]); 251*a69892caSSiarzhuk Zharski gDeviceNames[i] = NULL; 252*a69892caSSiarzhuk Zharski } 253*a69892caSSiarzhuk Zharski 254*a69892caSSiarzhuk Zharski MutexLocker driverLock; 255*a69892caSSiarzhuk Zharski 256*a69892caSSiarzhuk Zharski int32 deviceCount = 0; 257*a69892caSSiarzhuk Zharski for (int32 i = 0; i < MAX_DEVICES; i++) { 258*a69892caSSiarzhuk Zharski if (gDevices[i] == NULL) 259*a69892caSSiarzhuk Zharski continue; 260*a69892caSSiarzhuk Zharski 261*a69892caSSiarzhuk Zharski gDeviceNames[deviceCount] = (char*)malloc(strlen(sDeviceBaseName) + 4); 262*a69892caSSiarzhuk Zharski if (gDeviceNames[deviceCount]) { 263*a69892caSSiarzhuk Zharski sprintf(gDeviceNames[deviceCount], "%s%ld", sDeviceBaseName, i + 1); 264*a69892caSSiarzhuk Zharski TRACE(INF, "publishing %s\n", gDeviceNames[deviceCount]); 265*a69892caSSiarzhuk Zharski deviceCount++; 266*a69892caSSiarzhuk Zharski } else 267*a69892caSSiarzhuk Zharski TRACE(ERR, "Error: out of memory during allocating device name.\n"); 268*a69892caSSiarzhuk Zharski } 269*a69892caSSiarzhuk Zharski 270*a69892caSSiarzhuk Zharski gDeviceNames[deviceCount] = NULL; 271*a69892caSSiarzhuk Zharski return (const char**)&gDeviceNames[0]; 272*a69892caSSiarzhuk Zharski } 273*a69892caSSiarzhuk Zharski 274*a69892caSSiarzhuk Zharski 275*a69892caSSiarzhuk Zharski device_hooks* 276*a69892caSSiarzhuk Zharski find_device(const char* name) 277*a69892caSSiarzhuk Zharski { 278*a69892caSSiarzhuk Zharski static device_hooks deviceHooks = { 279*a69892caSSiarzhuk Zharski usb_audio_open, 280*a69892caSSiarzhuk Zharski usb_audio_close, 281*a69892caSSiarzhuk Zharski usb_audio_free, 282*a69892caSSiarzhuk Zharski usb_audio_control, 283*a69892caSSiarzhuk Zharski usb_audio_read, 284*a69892caSSiarzhuk Zharski usb_audio_write, 285*a69892caSSiarzhuk Zharski NULL, // select 286*a69892caSSiarzhuk Zharski NULL // deselect 287*a69892caSSiarzhuk Zharski }; 288*a69892caSSiarzhuk Zharski 289*a69892caSSiarzhuk Zharski return &deviceHooks; 290*a69892caSSiarzhuk Zharski } 291*a69892caSSiarzhuk Zharski 292