1 /*
2 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
3 * Distributed under the terms of the MIT License.
4 *
5 */
6
7 #include <KernelExport.h>
8 #include <Drivers.h>
9 #include <Errors.h>
10
11 #include <USB.h>
12 #include <malloc.h>
13 #include <string.h> /* strerror */
14 #include <stdlib.h> /* strtol */
15 #include <stdio.h> /* sprintf */
16
17
18 #include "usb_vision.h"
19 #include "tracing.h"
20
21 #define BASENAME_LEN 0x10 /*must be synchronized with below !!!*/
22 static const char *basename = "video/usb_vision/%u";
23
24 status_t usb_vision_device_added(const usb_device *dev, void **cookie);
25 status_t usb_vision_device_removed(void *cookie);
26
27 static usb_notify_hooks notify_hooks = {
28 &usb_vision_device_added,
29 &usb_vision_device_removed
30 };
31
32 struct usb_module_info *usb;
33 usb_vision_device *usb_vision_devices[DEVICES_COUNT];
34 char * usb_vision_names[DEVICES_COUNT + 1];
35 sem_id usb_vision_lock = -1;
36
37 struct usb_support_descriptor supported_devices[] = {
38 {0, 0, 0, 0x0573, 0x4d31},
39 };
40
41 /* init_hardware - called once the first time the driver is loaded */
init_hardware(void)42 status_t init_hardware (void){
43 TRACE("init_hardware\n"); /*special case - no file-logging activated now*/
44 return B_OK;
45 }
46
47 /* init_driver - optional function - called every time the driver is loaded. */
init_driver(void)48 status_t init_driver (void){
49 int i;
50 status_t status = B_OK;
51 load_setting();
52 create_log();
53
54 TRACE_FUNCALLS("init_driver\n");
55
56 if((status = get_module(B_USB_MODULE_NAME, (module_info **)&usb)) == B_OK){
57 if(usb){
58 for(i = 0; i < DEVICES_COUNT; i++)
59 usb_vision_devices[i] = 0;
60
61 usb_vision_names[0] = NULL;
62
63 (*usb->register_driver)(DRIVER_NAME, supported_devices, B_COUNT_OF(supported_devices), DRIVER_NAME);
64 (*usb->install_notify)(DRIVER_NAME, ¬ify_hooks);
65
66 usb_vision_lock = create_sem(1, DRIVER_NAME"_devices_table_lock");
67 }else{
68 status = B_ERROR;
69 TRACE_ALWAYS("init_driver failed: usb:%08x", usb);
70 }
71 }else
72 TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status, B_USB_MODULE_NAME);
73
74 TRACE_FUNCRET("init_driver returns:%08x\n", status);
75 return status;
76 }
77
78
79 /* uninit_driver - optional function - called every time the driver is unloaded */
uninit_driver(void)80 void uninit_driver (void){
81 int i;
82 TRACE_FUNCALLS("uninit_driver\n");
83
84 (*usb->uninstall_notify)(DRIVER_NAME);
85 acquire_sem(usb_vision_lock);
86
87 for(i = 0; i < DEVICES_COUNT; i++)
88 if(usb_vision_devices[i]){
89 free(usb_vision_devices[i]);
90 usb_vision_devices[i] = 0;
91 }
92
93 release_sem_etc(usb_vision_lock, 1, B_DO_NOT_RESCHEDULE);
94 delete_sem(usb_vision_lock);
95
96 for(i = 0; usb_vision_names[i]; i++)
97 free(usb_vision_names[i]);
98
99 put_module(B_USB_MODULE_NAME);
100 }
101
102
103 /* usb_vision_open - handle open() calls */
104
usb_vision_open(const char * name,uint32 flags,void ** cookie)105 static status_t usb_vision_open (const char *name, uint32 flags, void** cookie)
106 {
107 int i;
108 status_t status = ENODEV;
109 TRACE_FUNCALLS("usb_vision_open:%s flags:%d cookie:%08x\n", name, flags, cookie);
110
111 for(i = 0; i < DEVICES_COUNT; i++)
112 TRACE("%08x\n", usb_vision_devices[i]);
113
114 *cookie = NULL;
115 i = strtol(name + BASENAME_LEN, NULL, 10);
116 if(i >= 0 && i < DEVICES_COUNT){
117 acquire_sem(usb_vision_lock);
118 if(usb_vision_devices[i]){
119 if(atomic_add(&usb_vision_devices[i]->open_count, 1) == 0){
120 *cookie = usb_vision_devices[i];
121 TRACE("cookie in open:%08x\n", *cookie);
122 status = B_OK;
123 }else{
124 atomic_add(&usb_vision_devices[i]->open_count, -1);
125 status = B_BUSY;
126 }
127 }
128 release_sem(usb_vision_lock);
129 }
130
131 TRACE_FUNCRET("usb_vision_open returns:%08x\n", status);
132 return status;
133 }
134
135 /* usb_vision_read - handle read() calls */
136
usb_vision_read(void * cookie,off_t position,void * buf,size_t * num_bytes)137 static status_t usb_vision_read (void* cookie, off_t position, void *buf, size_t* num_bytes)
138 {
139 *num_bytes = 0; /* tell caller nothing was read */
140 return B_IO_ERROR;
141 }
142
143
144 /* usb_vision_write - handle write() calls */
145
usb_vision_write(void * cookie,off_t position,const void * buffer,size_t * num_bytes)146 static status_t usb_vision_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes)
147 {
148 *num_bytes = 0; /* tell caller nothing was written */
149 return B_IO_ERROR;
150 }
151
xet_nt_register(bool is_read,usb_vision_device * uvd,xet_nt100x_reg * ri)152 static status_t xet_nt_register(bool is_read, usb_vision_device *uvd, xet_nt100x_reg *ri)
153 {
154 status_t status = B_ERROR;
155 //uint8 req_type = USB_REQTYPE_VENDOR | (is_read ? USB_REQTYPE_DEVICE_IN : USB_REQTYPE_DEVICE_OUT);
156
157 TRACE_FUNCALLS("set_nt_register:%08x, %08x\n", uvd, ri);
158 TRACE_FUNCRES(trace_reginfo, ri);
159
160 //(*usb->send_request)(uvd->dev, req_type,
161 // )
162
163 TRACE_FUNCRET("set_nt_register returns:%08x\n", status);
164 return status;
165 }
166
167 /* usb_vision_control - handle ioctl calls */
usb_vision_control(void * cookie,uint32 op,void * arg,size_t len)168 static status_t usb_vision_control (void* cookie, uint32 op, void* arg, size_t len)
169 {
170 status_t status = B_BAD_VALUE;
171 TRACE_FUNCALLS("usb_vision_control:%08x, %d, %08x, %d\n", cookie, op, arg, len);
172 switch(op){
173 case NT_IOCTL_READ_REGISTER:
174 status = xet_nt_register(true, (usb_vision_device *)cookie, (xet_nt100x_reg *) arg);
175 break;
176 case NT_IOCTL_WRITE_REGISTER:
177 status = xet_nt_register(false, (usb_vision_device *)cookie, (xet_nt100x_reg *) arg);
178 break;
179 default:
180 break;
181 }
182 TRACE_FUNCRET("usb_vision_control returns:%08x\n", status);
183 return status;
184 }
185
186 /* usb_vision_close - handle close() calls */
usb_vision_close(void * cookie)187 static status_t usb_vision_close (void* cookie)
188 {
189 status_t status = B_OK;//ENODEV;
190 TRACE_FUNCALLS("usb_vision_close:%08x\n", cookie);
191
192 TRACE_FUNCRET("usb_vision_close returns:%08x\n", status);
193 return status;
194 }
195
196
197 /* usb_vision_free - called after the last device is closed, and after all i/o is complete. */
usb_vision_free(void * cookie)198 static status_t usb_vision_free (void* cookie)
199 {
200 status_t status = B_OK;
201 TRACE_FUNCALLS("usb_vision_free:%08x\n", cookie);
202
203 if(cookie){
204 usb_vision_device *uvd = (usb_vision_device *)cookie;
205 atomic_add(&uvd->open_count, -1);
206 }
207
208 TRACE_FUNCRET("usb_vision_free returns:%08x\n", status);
209 return status;
210 }
211
212 /* function pointers for the device hooks entry points */
213 device_hooks usb_vision_hooks = {
214 usb_vision_open, /* -> open entry point */
215 usb_vision_close, /* -> close entry point */
216 usb_vision_free, /* -> free cookie */
217 usb_vision_control, /* -> control entry point */
218 usb_vision_read, /* -> read entry point */
219 usb_vision_write /* -> write entry point */
220 };
221
222 /* publish_devices - return a null-terminated array of devices
223 supported by this driver. */
224
publish_devices()225 const char** publish_devices(){
226 int i, j;
227 TRACE_FUNCALLS("publish_devices\n");
228
229 for(i=0; usb_vision_names[i]; i++)
230 free(usb_vision_names[i]);
231
232 acquire_sem(usb_vision_lock);
233 for(i=0, j=0; i < DEVICES_COUNT; i++){
234 if(usb_vision_devices[i]){
235 usb_vision_names[j] = malloc(strlen(basename + 2));
236 if(usb_vision_names[j]){
237 sprintf(usb_vision_names[j], basename, i);
238 j++;
239 }
240 else
241 TRACE_ALWAYS("publish_devices - NO MEMORY\n");
242 }
243 }
244 usb_vision_names[j] = NULL;
245 release_sem(usb_vision_lock);
246
247 return (const char **)&usb_vision_names[0];
248 }
249
250 /* find_device - return ptr to device hooks structure for a
251 given device name */
find_device(const char * name)252 device_hooks* find_device(const char* name){
253 TRACE_FUNCALLS("find_device(%s)\n", name);
254 return &usb_vision_hooks;
255 }
256
create_add_device(usb_vision_device * uvd,const struct usb_configuration_info * uci,struct usb_endpoint_info * control_epi,struct usb_endpoint_info * data_epi)257 static status_t create_add_device(usb_vision_device *uvd, const struct usb_configuration_info *uci,
258 struct usb_endpoint_info *control_epi,
259 struct usb_endpoint_info *data_epi){
260 // char name[32];
261 status_t status = ENODEV;
262 // size_t buf_len;
263 int i = 0;
264
265 TRACE_FUNCALLS("create_add_device(%08x, %08x, %08x, %08x)\n", uvd, uci, control_epi, data_epi);
266
267 acquire_sem(usb_vision_lock);
268
269 for(i = 0; i < DEVICES_COUNT; i++){
270 if(usb_vision_devices[i] != NULL)
271 continue;
272
273 usb_vision_devices[i] = uvd;
274 /*
275 usd->active = 1;
276 usd->open = 0;
277
278 sprintf(name, "usb_vision:%d:done_read", i );
279 usd->done_read = create_sem(0, name);
280
281 sprintf(name, "usb_vision:%d:done_write", i);
282 usd->done_write = create_sem(0, name);
283
284 usd->tty = NULL;
285
286 buf_len = usd->read_buffer_size + usd->write_buffer_size + usd->interrupt_buffer_size;
287
288 usd->buffers_area = create_area("usb_serial:buffers_area", (void *)&usd->read_buffer, B_ANY_KERNEL_ADDRESS,
289 ROUNDUP(buf_len, B_PAGE_SIZE),
290 B_CONTIGUOUS, B_READ_AREA|B_WRITE_AREA);
291
292 usd->write_buffer = usd->read_buffer + usd->read_buffer_size;
293 usd->interrupt_buffer = usd->write_buffer + usd->write_buffer_size;
294 */
295 (*usb->set_configuration)(uvd->dev, uci);
296
297 uvd->control_pipe = control_epi->handle;
298 uvd->data_pipe = data_epi->handle;
299
300 status = B_OK;
301 break;
302 }
303 release_sem(usb_vision_lock);
304
305 TRACE_FUNCRET("add_device returns:%08x\n", status);
306 return status;
307 }
308
add_device(usb_vision_device * uvd,const usb_configuration_info * uci)309 static status_t add_device(usb_vision_device *uvd, const usb_configuration_info *uci){
310 usb_endpoint_info *control_epi = NULL;
311 usb_endpoint_info *data_epi = NULL;
312 status_t status = ENODEV;
313 int i = 0;
314 usb_interface_info *uii = uci->interface[0].active;
315 TRACE_FUNCALLS("> add_device(%08x, %08x)\n", uvd, uci);
316
317 for(i=0; i < uii->endpoint_count; i++){
318 if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_ISOCHRONOUS){
319 if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN) == USB_EP_ADDR_DIR_IN){
320 data_epi = &uii->endpoint[i];
321 TRACE("iso_ep:%d\n", i);
322 }
323 }
324 if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_CONTROL){
325 control_epi = &uii->endpoint[i];
326 TRACE("cont_ep:%d\n", i);
327 }
328 if(control_epi && data_epi)
329 break;
330 }
331
332 if(control_epi && data_epi){
333 status = create_add_device(uvd, uci, control_epi, data_epi);
334 }
335
336 TRACE_FUNCRET("< create_add_device returns:%08x\n", status);
337 return status;
338 }
339
usb_vision_device_added(const usb_device * dev,void ** cookie)340 status_t usb_vision_device_added(const usb_device *dev, void **cookie){
341 int dev_idx;
342 status_t status = B_OK;
343 const usb_device_descriptor *udd;
344 usb_vision_device *uvd = 0;
345 TRACE_FUNCALLS("usb_vision_device_added:%08x cookie:%08x\n", dev, cookie);
346
347 udd = (*usb->get_device_descriptor)(dev);
348 TRACE_ALWAYS("Probing device: %08x/%08x\n", udd->vendor_id, udd->product_id);
349
350 *cookie = 0;
351 for(dev_idx = 0; dev_idx < B_COUNT_OF(supported_devices); dev_idx++)
352 if(supported_devices[dev_idx].vendor == udd->vendor_id
353 && supported_devices[dev_idx].product == udd->product_id){
354 const usb_configuration_info *uci;
355 int cfg_idx;
356 for(cfg_idx = 0; (uci = (*usb->get_nth_configuration)(dev, cfg_idx)) != NULL; cfg_idx++){
357 uvd = malloc(sizeof(usb_vision_device));
358 if(uvd){
359 memset(uvd, 0, sizeof(usb_vision_device));
360 uvd->dev = dev;
361 if((status = add_device(uvd, uci)) == B_OK){
362 *cookie = (void *)dev;
363 TRACE_ALWAYS("(%04x/%04x) added \n", supported_devices[dev_idx].vendor,
364 supported_devices[dev_idx].product);
365 break;
366 }else
367 free(uvd);
368 }else
369 status = B_NO_MEMORY;
370 }
371 break;
372 }
373
374 TRACE_FUNCRET("usb_vision_device_added returns:%08x\n", status);
375 return status;
376 }
377
usb_vision_device_removed(void * cookie)378 status_t usb_vision_device_removed(void *cookie){
379 int i;
380 status_t status = B_OK;
381 struct usb_device *ud = (struct usb_device *) cookie;
382 TRACE_FUNCALLS("usb_vision_device_removed:%08x\n", cookie);
383
384 acquire_sem(usb_vision_lock);
385
386 for(i = 0; i < DEVICES_COUNT; i++ ){
387 usb_vision_device *uvd = usb_vision_devices[i];
388 if(uvd){
389 if(ud == uvd->dev){
390 free(uvd);
391 usb_vision_devices[i] = 0;
392 }
393 }
394 }
395
396 release_sem(usb_vision_lock);
397
398 TRACE_FUNCRET("usb_vision_device_removed returns:%08x\n", status);
399 return status;
400 }
401