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 */ 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. */ 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 */ 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 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 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 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 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 */ 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 */ 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. */ 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 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 */ 252 device_hooks* find_device(const char* name){ 253 TRACE_FUNCALLS("find_device(%s)\n", name); 254 return &usb_vision_hooks; 255 } 256 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 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 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 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