xref: /haiku/src/add-ons/kernel/drivers/audio/usb/Driver.cpp (revision a69892cadca9288b901ac66273d342bfb4329373)
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, &notifyHooks);
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