1 /* 2 * Copyright 2005, Jérôme DUVAL. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <Drivers.h> 7 #include <OS.h> 8 #include <bus_manager.h> 9 #include <malloc.h> 10 #include <module.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <sys/ioccom.h> 14 #include <sys/ioctl.h> 15 16 #define __KERNEL__ 17 #include <pcmcia/cs_types.h> 18 #include <pcmcia/cs.h> 19 #include <pcmcia/cistpl.h> 20 #include <pcmcia/ds.h> 21 22 #define copy_from_user memcpy 23 #define copy_to_user memcpy 24 #define CardServices gPcmciaCs->_CardServices 25 26 const char sockname[] = "bus/pcmcia/sock/%d"; 27 static char ** devices; 28 uint32 devices_count = 0; 29 30 int32 api_version = B_CUR_DRIVER_API_VERSION; 31 32 cs_client_module_info *gPcmciaCs; 33 ds_module_info *gPcmciaDs; 34 35 static status_t 36 ds_open(const char *name, uint32 flags, void **_cookie) 37 { 38 int32 socket = -1; 39 int32 i; 40 *_cookie = NULL; 41 42 for (i=0; i<devices_count; i++) { 43 if (strcmp(name, devices[i]) == 0) { 44 socket = i; 45 break; 46 } 47 } 48 49 if (socket < 0) { 50 return B_BAD_VALUE; 51 } 52 53 if (gPcmciaDs->get_handle(socket, (client_handle_t *)_cookie) != B_OK) { 54 return ENODEV; 55 } 56 57 return B_OK; 58 } 59 60 61 static status_t 62 ds_close(void *cookie) 63 { 64 return B_OK; 65 } 66 67 68 static status_t 69 ds_free(void *cookie) 70 { 71 return B_OK; 72 } 73 74 75 static status_t 76 ds_read(void *cookie, off_t position, void *data, size_t *numBytes) 77 { 78 return B_ERROR; 79 } 80 81 82 static status_t 83 ds_write(void *cookie, off_t position, const void *data, size_t *numBytes) 84 { 85 return B_ERROR; 86 } 87 88 89 /*====================================================================*/ 90 91 static status_t 92 ds_ioctl(void *cookie, uint32 cmd, void *arg, size_t len) 93 { 94 /*socket_info_t *s = (socket_info_t *) cookie; 95 u_int size = IOCPARM_LEN(cmd); 96 status_t ret, err; 97 ds_ioctl_arg_t buf; 98 99 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; 100 101 err = ret = 0; 102 103 if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size); 104 105 switch (cmd) { 106 case DS_ADJUST_RESOURCE_INFO: 107 ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust); 108 break; 109 case DS_GET_CARD_SERVICES_INFO: 110 ret = CardServices(GetCardServicesInfo, &buf.servinfo); 111 break; 112 case DS_GET_CONFIGURATION_INFO: 113 ret = CardServices(GetConfigurationInfo, s->handle, &buf.config); 114 break; 115 case DS_GET_FIRST_TUPLE: 116 ret = CardServices(GetFirstTuple, s->handle, &buf.tuple); 117 break; 118 case DS_GET_NEXT_TUPLE: 119 ret = CardServices(GetNextTuple, s->handle, &buf.tuple); 120 break; 121 case DS_GET_TUPLE_DATA: 122 buf.tuple.TupleData = buf.tuple_parse.data; 123 buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); 124 ret = CardServices(GetTupleData, s->handle, &buf.tuple); 125 break; 126 case DS_PARSE_TUPLE: 127 buf.tuple.TupleData = buf.tuple_parse.data; 128 ret = CardServices(ParseTuple, s->handle, &buf.tuple, 129 &buf.tuple_parse.parse); 130 break; 131 case DS_RESET_CARD: 132 ret = CardServices(ResetCard, s->handle, NULL); 133 break; 134 case DS_GET_STATUS: 135 ret = CardServices(GetStatus, s->handle, &buf.status); 136 break; 137 case DS_VALIDATE_CIS: 138 ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo); 139 break; 140 case DS_SUSPEND_CARD: 141 ret = CardServices(SuspendCard, s->handle, NULL); 142 break; 143 case DS_RESUME_CARD: 144 ret = CardServices(ResumeCard, s->handle, NULL); 145 break; 146 case DS_EJECT_CARD: 147 ret = CardServices(EjectCard, s->handle, NULL); 148 break; 149 case DS_INSERT_CARD: 150 ret = CardServices(InsertCard, s->handle, NULL); 151 break; 152 case DS_ACCESS_CONFIGURATION_REGISTER: 153 if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) 154 return -EPERM; 155 ret = CardServices(AccessConfigurationRegister, s->handle, 156 &buf.conf_reg); 157 break; 158 case DS_GET_FIRST_REGION: 159 ret = CardServices(GetFirstRegion, s->handle, &buf.region); 160 break; 161 case DS_GET_NEXT_REGION: 162 ret = CardServices(GetNextRegion, s->handle, &buf.region); 163 break; 164 case DS_GET_FIRST_WINDOW: 165 buf.win_info.handle = (window_handle_t)s->handle; 166 ret = CardServices(GetFirstWindow, &buf.win_info.handle, 167 &buf.win_info.window); 168 break; 169 case DS_GET_NEXT_WINDOW: 170 ret = CardServices(GetNextWindow, &buf.win_info.handle, 171 &buf.win_info.window); 172 break; 173 case DS_GET_MEM_PAGE: 174 ret = CardServices(GetMemPage, buf.win_info.handle, 175 &buf.win_info.map); 176 break; 177 case DS_REPLACE_CIS: 178 ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump); 179 break; 180 */ 181 client_handle_t h = (client_handle_t) cookie; 182 u_int size = IOCPARM_LEN(cmd); 183 status_t ret, err; 184 ds_ioctl_arg_t buf; 185 186 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; 187 188 err = ret = 0; 189 190 if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size); 191 192 switch (cmd) { 193 case DS_ADJUST_RESOURCE_INFO: 194 ret = CardServices(AdjustResourceInfo, h, &buf.adjust); 195 break; 196 case DS_GET_CARD_SERVICES_INFO: 197 ret = CardServices(GetCardServicesInfo, &buf.servinfo); 198 break; 199 case DS_GET_CONFIGURATION_INFO: 200 ret = CardServices(GetConfigurationInfo, h, &buf.config); 201 break; 202 case DS_GET_FIRST_TUPLE: 203 ret = CardServices(GetFirstTuple, h, &buf.tuple); 204 break; 205 case DS_GET_NEXT_TUPLE: 206 ret = CardServices(GetNextTuple, h, &buf.tuple); 207 break; 208 case DS_GET_TUPLE_DATA: 209 buf.tuple.TupleData = buf.tuple_parse.data; 210 buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); 211 ret = CardServices(GetTupleData, h, &buf.tuple); 212 break; 213 case DS_PARSE_TUPLE: 214 buf.tuple.TupleData = buf.tuple_parse.data; 215 ret = CardServices(ParseTuple, h, &buf.tuple, 216 &buf.tuple_parse.parse); 217 break; 218 case DS_RESET_CARD: 219 ret = CardServices(ResetCard, h, NULL); 220 break; 221 case DS_GET_STATUS: 222 ret = CardServices(GetStatus, h, &buf.status); 223 break; 224 case DS_VALIDATE_CIS: 225 ret = CardServices(ValidateCIS, h, &buf.cisinfo); 226 break; 227 case DS_SUSPEND_CARD: 228 ret = CardServices(SuspendCard, h, NULL); 229 break; 230 case DS_RESUME_CARD: 231 ret = CardServices(ResumeCard, h, NULL); 232 break; 233 case DS_EJECT_CARD: 234 ret = CardServices(EjectCard, h, NULL); 235 break; 236 case DS_INSERT_CARD: 237 ret = CardServices(InsertCard, h, NULL); 238 break; 239 /* case DS_ACCESS_CONFIGURATION_REGISTER: 240 if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) 241 return -EPERM; 242 ret = CardServices(AccessConfigurationRegister, h, 243 &buf.conf_reg); 244 break; 245 case DS_GET_FIRST_REGION: 246 ret = CardServices(GetFirstRegion, h, &buf.region); 247 break; 248 case DS_GET_NEXT_REGION: 249 ret = CardServices(GetNextRegion, h, &buf.region); 250 break; 251 case DS_GET_FIRST_WINDOW: 252 buf.win_info.handle = (window_handle_t)h; 253 ret = CardServices(GetFirstWindow, &buf.win_info.handle, 254 &buf.win_info.window); 255 break; 256 case DS_GET_NEXT_WINDOW: 257 ret = CardServices(GetNextWindow, &buf.win_info.handle, 258 &buf.win_info.window); 259 break; 260 case DS_GET_MEM_PAGE: 261 ret = CardServices(GetMemPage, buf.win_info.handle, 262 &buf.win_info.map); 263 break;*/ 264 case DS_REPLACE_CIS: 265 ret = CardServices(ReplaceCIS, h, &buf.cisdump); 266 break; 267 268 /* case DS_BIND_REQUEST: 269 if (!capable(CAP_SYS_ADMIN)) return -EPERM; 270 err = bind_request(i, &buf.bind_info); 271 break; 272 case DS_GET_DEVICE_INFO: 273 err = get_device_info(i, &buf.bind_info, 1); 274 break; 275 case DS_GET_NEXT_DEVICE: 276 err = get_device_info(i, &buf.bind_info, 0); 277 break; 278 case DS_UNBIND_REQUEST: 279 err = unbind_request(i, &buf.bind_info); 280 break; 281 case DS_BIND_MTD: 282 if (!capable(CAP_SYS_ADMIN)) return -EPERM; 283 err = bind_mtd(i, &buf.mtd_info); 284 break;*/ 285 default: 286 err = -EINVAL; 287 } 288 289 if ((err == 0) && (ret != CS_SUCCESS)) { 290 switch (ret) { 291 case CS_BAD_SOCKET: case CS_NO_CARD: 292 err = ENODEV; break; 293 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: 294 case CS_BAD_TUPLE: 295 err = EINVAL; break; 296 case CS_IN_USE: 297 err = EBUSY; break; 298 case CS_OUT_OF_RESOURCE: 299 err = ENOSPC; break; 300 case CS_NO_MORE_ITEMS: 301 err = ENODATA; break; 302 case CS_UNSUPPORTED_FUNCTION: 303 err = ENOSYS; break; 304 default: 305 err = EIO; break; 306 } 307 } 308 309 if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size); 310 311 return err; 312 } /* ds_ioctl */ 313 314 315 status_t 316 init_hardware() 317 { 318 return B_OK; 319 } 320 321 322 const char ** 323 publish_devices(void) 324 { 325 return (const char **)devices; 326 } 327 328 329 static device_hooks hooks = { 330 &ds_open, 331 &ds_close, 332 &ds_free, 333 &ds_ioctl, 334 &ds_read, 335 &ds_write, 336 NULL, 337 NULL, 338 NULL, 339 NULL 340 }; 341 342 device_hooks * 343 find_device(const char *name) 344 { 345 return &hooks; 346 } 347 348 349 status_t 350 init_driver() 351 { 352 status_t err; 353 client_handle_t handle; 354 uint32 i; 355 356 #if DEBUG 357 load_driver_symbols("ds"); 358 #endif 359 360 if ((err = get_module(CS_CLIENT_MODULE_NAME, (module_info **)&gPcmciaCs))!=B_OK) 361 return err; 362 if ((err = get_module(DS_MODULE_NAME, (module_info **)&gPcmciaDs))!=B_OK) { 363 put_module(CS_CLIENT_MODULE_NAME); 364 return err; 365 } 366 367 devices_count = 0; 368 while (gPcmciaDs->get_handle(devices_count, &handle)==B_OK) { 369 devices_count++; 370 } 371 372 if (devices_count <= 0) 373 return ENODEV; 374 375 devices = malloc(sizeof(char *) * (devices_count+1)); 376 for (i=0; i<devices_count; i++) { 377 devices[i] = strdup(sockname); 378 sprintf(devices[i], sockname, i); 379 } 380 devices[devices_count] = NULL; 381 382 return B_OK; 383 } 384 385 386 void 387 uninit_driver() 388 { 389 int32 i = 0; 390 for (i=0; i<devices_count; i++) { 391 free (devices[i]); 392 } 393 394 put_module(DS_MODULE_NAME); 395 put_module(CS_CLIENT_MODULE_NAME); 396 } 397