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