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]) { 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]) { 171 status = gECMDevices[index]->Open(); 172 *cookie = gECMDevices[index]; 173 } 174 175 mutex_unlock(&gDriverLock); 176 return status; 177 } 178 179 180 static status_t 181 usb_ecm_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 182 { 183 TRACE("read(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); 184 ECMDevice *device = (ECMDevice *)cookie; 185 return device->Read((uint8 *)buffer, numBytes); 186 } 187 188 189 static status_t 190 usb_ecm_write(void *cookie, off_t position, const void *buffer, 191 size_t *numBytes) 192 { 193 TRACE("write(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); 194 ECMDevice *device = (ECMDevice *)cookie; 195 return device->Write((const uint8 *)buffer, numBytes); 196 } 197 198 199 static status_t 200 usb_ecm_control(void *cookie, uint32 op, void *buffer, size_t length) 201 { 202 TRACE("control(%p, %lu, %p, %lu)\n", cookie, op, buffer, length); 203 ECMDevice *device = (ECMDevice *)cookie; 204 return device->Control(op, buffer, length); 205 } 206 207 208 static status_t 209 usb_ecm_close(void *cookie) 210 { 211 TRACE("close(%p)\n", cookie); 212 ECMDevice *device = (ECMDevice *)cookie; 213 return device->Close(); 214 } 215 216 217 static status_t 218 usb_ecm_free(void *cookie) 219 { 220 TRACE("free(%p)\n", cookie); 221 ECMDevice *device = (ECMDevice *)cookie; 222 mutex_lock(&gDriverLock); 223 status_t status = device->Free(); 224 for (int32 i = 0; i < MAX_DEVICES; i++) { 225 if (gECMDevices[i] == device) { 226 // the device is removed already but as it was open the 227 // removed hook has not deleted the object 228 gECMDevices[i] = NULL; 229 delete device; 230 break; 231 } 232 } 233 234 mutex_unlock(&gDriverLock); 235 return status; 236 } 237 238 239 const char ** 240 publish_devices() 241 { 242 TRACE("publish_devices()\n"); 243 for (int32 i = 0; gDeviceNames[i]; i++) { 244 free(gDeviceNames[i]); 245 gDeviceNames[i] = NULL; 246 } 247 248 int32 deviceCount = 0; 249 mutex_lock(&gDriverLock); 250 for (int32 i = 0; i < MAX_DEVICES; i++) { 251 if (gECMDevices[i] == NULL) 252 continue; 253 254 gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4); 255 if (gDeviceNames[deviceCount]) { 256 sprintf(gDeviceNames[deviceCount], "%s%" B_PRId32, sDeviceBaseName, 257 i); 258 TRACE("publishing %s\n", gDeviceNames[deviceCount]); 259 deviceCount++; 260 } else 261 TRACE_ALWAYS("publish_devices - no memory to allocate device name\n"); 262 } 263 264 gDeviceNames[deviceCount] = NULL; 265 mutex_unlock(&gDriverLock); 266 return (const char **)&gDeviceNames[0]; 267 } 268 269 270 device_hooks * 271 find_device(const char *name) 272 { 273 TRACE("find_device(%s)\n", name); 274 static device_hooks deviceHooks = { 275 usb_ecm_open, 276 usb_ecm_close, 277 usb_ecm_free, 278 usb_ecm_control, 279 usb_ecm_read, 280 usb_ecm_write, 281 NULL, /* select */ 282 NULL /* deselect */ 283 }; 284 285 return &deviceHooks; 286 } 287