xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/Driver.cpp (revision 8a04709a1d4086fecf352cc079c97e394f1a4ba3)
1 /*
2  * Copyright (c) 2007-2008 by Michael Lotz
3  * Heavily based on the original usb_serial driver which is:
4  *
5  * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
6  * Distributed under the terms of the MIT License.
7  */
8 #include <KernelExport.h>
9 #include <Drivers.h>
10 #include <malloc.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #include "Driver.h"
15 #include "SerialDevice.h"
16 #include "USB3.h"
17 
18 static const char *sDeviceBaseName = "ports/usb";
19 SerialDevice *gSerialDevices[DEVICES_COUNT];
20 char *gDeviceNames[DEVICES_COUNT + 1];
21 usb_module_info *gUSBModule = NULL;
22 tty_module_info *gTTYModule = NULL;
23 struct ddomain gSerialDomain;
24 sem_id gDriverLock = -1;
25 
26 
27 status_t
28 usb_serial_device_added(usb_device device, void **cookie)
29 {
30 	TRACE_FUNCALLS("> usb_serial_device_added(0x%08x, 0x%08x)\n", device, cookie);
31 
32 	status_t status = B_OK;
33 	const usb_device_descriptor *descriptor
34 		= gUSBModule->get_device_descriptor(device);
35 
36 	TRACE_ALWAYS("probing device: 0x%04x/0x%04x\n", descriptor->vendor_id,
37 		descriptor->product_id);
38 
39 	*cookie = NULL;
40 	SerialDevice *serialDevice = SerialDevice::MakeDevice(device,
41 		descriptor->vendor_id, descriptor->product_id);
42 
43 	const usb_configuration_info *configuration
44 		= gUSBModule->get_nth_configuration(device, 0);
45 
46 	if (!configuration)
47 		return B_ERROR;
48 
49 	status = serialDevice->AddDevice(configuration);
50 	if (status < B_OK) {
51 		delete serialDevice;
52 		return status;
53 	}
54 
55 	acquire_sem(gDriverLock);
56 	for (int32 i = 0; i < DEVICES_COUNT; i++) {
57 		if (gSerialDevices[i] != NULL)
58 			continue;
59 
60 		status = serialDevice->Init();
61 		if (status < B_OK) {
62 			delete serialDevice;
63 			return status;
64 		}
65 
66 		gSerialDevices[i] = serialDevice;
67 		*cookie = serialDevice;
68 
69 		release_sem(gDriverLock);
70 		TRACE_ALWAYS("%s (0x%04x/0x%04x) added\n", serialDevice->Description(),
71 			descriptor->vendor_id, descriptor->product_id);
72 		return B_OK;
73 	}
74 
75 	release_sem(gDriverLock);
76 	return B_ERROR;
77 }
78 
79 
80 status_t
81 usb_serial_device_removed(void *cookie)
82 {
83 	TRACE_FUNCALLS("> usb_serial_device_removed(0x%08x)\n", cookie);
84 
85 	acquire_sem(gDriverLock);
86 
87 	SerialDevice *device = (SerialDevice *)cookie;
88 	for (int32 i = 0; i < DEVICES_COUNT; i++) {
89 		if (gSerialDevices[i] == device) {
90 			delete device;
91 			gSerialDevices[i] = NULL;
92 			break;
93 		}
94 	}
95 
96 	release_sem(gDriverLock);
97 	TRACE_FUNCRET("< usb_serial_device_removed() returns\n");
98 	return B_OK;
99 }
100 
101 
102 //#pragma mark -
103 
104 
105 /* init_hardware - called once the first time the driver is loaded */
106 status_t
107 init_hardware()
108 {
109 	TRACE("init_hardware\n");
110 	return B_OK;
111 }
112 
113 
114 /* init_driver - called every time the driver is loaded. */
115 status_t
116 init_driver()
117 {
118 	load_settings();
119 	create_log_file();
120 
121 	TRACE_FUNCALLS("> init_driver()\n");
122 
123 	status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule);
124 	if (status < B_OK)
125 		return status;
126 
127 	status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
128 	if (status < B_OK) {
129 		put_module(B_TTY_MODULE_NAME);
130 		return status;
131 	}
132 
133 	for (int32 i = 0; i < DEVICES_COUNT; i++)
134 		gSerialDevices[i] = 0;
135 
136 	gDeviceNames[0] = NULL;
137 	//load_driver_symbols(DRIVER_NAME);
138 
139 	gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock");
140 	if (gDriverLock < B_OK) {
141 		put_module(B_USB_MODULE_NAME);
142 		put_module(B_TTY_MODULE_NAME);
143 		return gDriverLock;
144 	}
145 
146 	static usb_notify_hooks notifyHooks = {
147 		&usb_serial_device_added,
148 		&usb_serial_device_removed
149 	};
150 
151 	gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
152 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
153 	TRACE_FUNCRET("< init_driver() returns\n");
154 	return B_OK;
155 }
156 
157 
158 /* uninit_driver - called every time the driver is unloaded */
159 void
160 uninit_driver()
161 {
162 	TRACE_FUNCALLS("> uninit_driver()\n");
163 
164 	gUSBModule->uninstall_notify(DRIVER_NAME);
165 	acquire_sem(gDriverLock);
166 
167 	for (int32 i = 0; i < DEVICES_COUNT; i++) {
168 		if (gSerialDevices[i]) {
169 			delete gSerialDevices[i];
170 			gSerialDevices[i] = NULL;
171 		}
172 	}
173 
174 	for (int32 i = 0; gDeviceNames[i]; i++)
175 		free(gDeviceNames[i]);
176 
177 	delete_sem(gDriverLock);
178 	put_module(B_USB_MODULE_NAME);
179 	put_module(B_TTY_MODULE_NAME);
180 
181 	TRACE_FUNCRET("< uninit_driver() returns\n");
182 }
183 
184 
185 bool
186 usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags)
187 {
188 	TRACE_FUNCALLS("> usb_serial_service(0x%08x, 0x%08x, 0x%08x)\n", ptty, ddr, flags);
189 
190 	for (int32 i = 0; i < DEVICES_COUNT; i++) {
191 		if (gSerialDevices[i] && gSerialDevices[i]->Service(ptty, ddr, flags)) {
192 			TRACE_FUNCRET("< usb_serial_service() returns: true\n");
193 			return true;
194 		}
195 	}
196 
197 	TRACE_FUNCRET("< usb_serial_service() returns: false\n");
198 	return false;
199 }
200 
201 
202 /* usb_serial_open - handle open() calls */
203 static status_t
204 usb_serial_open(const char *name, uint32 flags, void **cookie)
205 {
206 	TRACE_FUNCALLS("> usb_serial_open(%s, 0x%08x, 0x%08x)\n", name, flags, cookie);
207 	acquire_sem(gDriverLock);
208 	status_t status = ENODEV;
209 
210 	*cookie = NULL;
211 	int i = strtol(name + strlen(sDeviceBaseName), NULL, 10);
212 	if (i >= 0 && i < DEVICES_COUNT && gSerialDevices[i]) {
213 		status = gSerialDevices[i]->Open(flags);
214 		*cookie = gSerialDevices[i];
215 	}
216 
217 	release_sem(gDriverLock);
218 	TRACE_FUNCRET("< usb_serial_open() returns: 0x%08x\n", status);
219 	return status;
220 }
221 
222 
223 /* usb_serial_read - handle read() calls */
224 static status_t
225 usb_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
226 {
227 	TRACE_FUNCALLS("> usb_serial_read(0x%08x, %Ld, 0x%08x, %d)\n", cookie,
228 		position, buffer, *numBytes);
229 	SerialDevice *device = (SerialDevice *)cookie;
230 	return device->Read((char *)buffer, numBytes);
231 }
232 
233 
234 /* usb_serial_write - handle write() calls */
235 static status_t
236 usb_serial_write(void *cookie, off_t position, const void *buffer,
237 	size_t *numBytes)
238 {
239 	TRACE_FUNCALLS("> usb_serial_write(0x%08x, %Ld, 0x%08x, %d)\n", cookie,
240 		position, buffer, *numBytes);
241 	SerialDevice *device = (SerialDevice *)cookie;
242 	return device->Write((const char *)buffer, numBytes);
243 }
244 
245 
246 /* usb_serial_control - handle ioctl calls */
247 static status_t
248 usb_serial_control(void *cookie, uint32 op, void *arg, size_t length)
249 {
250 	TRACE_FUNCALLS("> usb_serial_control(0x%08x, 0x%08x, 0x%08x, %d)\n",
251 		cookie, op, arg, length);
252 	SerialDevice *device = (SerialDevice *)cookie;
253 	return device->Control(op, arg, length);
254 }
255 
256 
257 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
258 /* usb_serial_select - handle select start */
259 static status_t
260 usb_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
261 {
262 	TRACE_FUNCALLS("> usb_serial_select(0x%08x, 0x%08x, 0x%08x, %p)\n",
263 		cookie, event, ref, sync);
264 	SerialDevice *device = (SerialDevice *)cookie;
265 	return device->Select(event, ref, sync);
266 }
267 
268 
269 /* usb_serial_deselect - handle select exit */
270 static status_t
271 usb_serial_deselect(void *cookie, uint8 event, selectsync *sync)
272 {
273 	TRACE_FUNCALLS("> usb_serial_deselect(0x%08x, 0x%08x, %p)\n",
274 		cookie, event, sync);
275 	SerialDevice *device = (SerialDevice *)cookie;
276 	return device->DeSelect(event, sync);
277 }
278 #endif // DANO, HAIKU
279 
280 
281 /* usb_serial_close - handle close() calls */
282 static status_t
283 usb_serial_close(void *cookie)
284 {
285 	TRACE_FUNCALLS("> usb_serial_close(0x%08x)\n", cookie);
286 	SerialDevice *device = (SerialDevice *)cookie;
287 	return device->Close();
288 }
289 
290 
291 /* usb_serial_free - called after last device is closed, and all i/o complete. */
292 static status_t
293 usb_serial_free(void *cookie)
294 {
295 	TRACE_FUNCALLS("> usb_serial_free(0x%08x)\n", cookie);
296 	SerialDevice *device = (SerialDevice *)cookie;
297 	return device->Free();
298 }
299 
300 
301 /* publish_devices - null-terminated array of devices supported by this driver. */
302 const char **
303 publish_devices()
304 {
305 	TRACE_FUNCALLS("> publish_devices()\n");
306 	for (int32 i = 0; gDeviceNames[i]; i++)
307 		free(gDeviceNames[i]);
308 
309 	int32 j = 0;
310 	acquire_sem(gDriverLock);
311 	for(int32 i = 0; i < DEVICES_COUNT; i++) {
312 		if (gSerialDevices[i]) {
313 			gDeviceNames[j] = (char *)malloc(strlen(sDeviceBaseName + 4));
314 			if (gDeviceNames[j]) {
315 				sprintf(gDeviceNames[j], "%s%ld", sDeviceBaseName, i);
316 				j++;
317 			} else
318 				TRACE_ALWAYS("publish_devices - no memory to allocate device names\n");
319 		}
320 	}
321 
322 	gDeviceNames[j] = NULL;
323 	release_sem(gDriverLock);
324 	return (const char **)&gDeviceNames[0];
325 }
326 
327 
328 /* find_device - return poiter to device hooks structure for a given device */
329 device_hooks *
330 find_device(const char *name)
331 {
332 	static device_hooks deviceHooks = {
333 		usb_serial_open,			/* -> open entry point */
334 		usb_serial_close,			/* -> close entry point */
335 		usb_serial_free,			/* -> free cookie */
336 		usb_serial_control,			/* -> control entry point */
337 		usb_serial_read,			/* -> read entry point */
338 		usb_serial_write,			/* -> write entry point */
339 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
340 		usb_serial_select,			/* -> select entry point */
341 		usb_serial_deselect			/* -> deselect entry point */
342 #endif
343 	};
344 
345 	TRACE_FUNCALLS("> find_device(%s)\n", name);
346 	return &deviceHooks;
347 }
348