|
|
1.1 ! root 1: /*====================================================================== ! 2: ! 3: PC Card Driver Services ! 4: ! 5: ds.c 1.115 2002/10/12 19:03:44 ! 6: ! 7: The contents of this file are subject to the Mozilla Public ! 8: License Version 1.1 (the "License"); you may not use this file ! 9: except in compliance with the License. You may obtain a copy of ! 10: the License at http://www.mozilla.org/MPL/ ! 11: ! 12: Software distributed under the License is distributed on an "AS ! 13: IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ! 14: implied. See the License for the specific language governing ! 15: rights and limitations under the License. ! 16: ! 17: The initial developer of the original code is David A. Hinds ! 18: <[email protected]>. Portions created by David A. Hinds ! 19: are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ! 20: ! 21: Alternatively, the contents of this file may be used under the ! 22: terms of the GNU General Public License version 2 (the "GPL"), in ! 23: which case the provisions of the GPL are applicable instead of the ! 24: above. If you wish to allow the use of your version of this file ! 25: only under the terms of the GPL and not to allow others to use ! 26: your version of this file under the MPL, indicate your decision ! 27: by deleting the provisions above and replace them with the notice ! 28: and other provisions required by the GPL. If you do not delete ! 29: the provisions above, a recipient may use your version of this ! 30: file under either the MPL or the GPL. ! 31: ! 32: ======================================================================*/ ! 33: ! 34: #include <linux/module.h> ! 35: #include <linux/init.h> ! 36: #include <linux/kernel.h> ! 37: #include <linux/major.h> ! 38: #include <linux/string.h> ! 39: #include <linux/errno.h> ! 40: #include <linux/slab.h> ! 41: #include <linux/mm.h> ! 42: #include <linux/fcntl.h> ! 43: #include <linux/sched.h> ! 44: #include <linux/timer.h> ! 45: #include <linux/ioctl.h> ! 46: #include <linux/proc_fs.h> ! 47: #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,23)) ! 48: #include <linux/poll.h> ! 49: #endif ! 50: ! 51: /* ! 52: * <pcmcia/cs.h> defines io_req_t which is not used in this file, but ! 53: * which clashes with the io_req_t needed for the Mach devices. Rename ! 54: * it to cardservice_io_req_t to avoid this clash. ! 55: */ ! 56: #define io_req_t cardservice_io_req_t ! 57: #include <pcmcia/version.h> ! 58: #include <pcmcia/cs_types.h> ! 59: #include <pcmcia/cs.h> ! 60: #include <pcmcia/bulkmem.h> ! 61: #include <pcmcia/cistpl.h> ! 62: #include <pcmcia/ds.h> ! 63: #undef io_req_t ! 64: ! 65: /*====================================================================*/ ! 66: ! 67: /* Module parameters */ ! 68: ! 69: MODULE_AUTHOR("David Hinds <[email protected]>"); ! 70: MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); ! 71: MODULE_LICENSE("Dual MPL/GPL"); ! 72: ! 73: #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") ! 74: ! 75: #ifdef PCMCIA_DEBUG ! 76: INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); ! 77: #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) ! 78: static const char *version = ! 79: "ds.c 1.115 2002/10/12 19:03:44 (David Hinds)"; ! 80: #else ! 81: #define DEBUG(n, args...) ! 82: #endif ! 83: ! 84: /*====================================================================*/ ! 85: ! 86: typedef struct driver_info_t { ! 87: dev_info_t dev_info; ! 88: int use_count, status; ! 89: dev_link_t *(*attach)(void); ! 90: void (*detach)(dev_link_t *); ! 91: struct driver_info_t *next; ! 92: } driver_info_t; ! 93: ! 94: typedef struct socket_bind_t { ! 95: driver_info_t *driver; ! 96: u_char function; ! 97: dev_link_t *instance; ! 98: struct socket_bind_t *next; ! 99: } socket_bind_t; ! 100: ! 101: /* Device user information */ ! 102: #define MAX_EVENTS 32 ! 103: #define USER_MAGIC 0x7ea4 ! 104: #define CHECK_USER(u) \ ! 105: (((u) == NULL) || ((u)->user_magic != USER_MAGIC)) ! 106: typedef struct user_info_t { ! 107: u_int user_magic; ! 108: int event_head, event_tail; ! 109: event_t event[MAX_EVENTS]; ! 110: struct user_info_t *next; ! 111: } user_info_t; ! 112: ! 113: /* Socket state information */ ! 114: typedef struct socket_info_t { ! 115: client_handle_t handle; ! 116: int state; ! 117: user_info_t *user; ! 118: int req_pending, req_result; ! 119: wait_queue_head_t queue, request; ! 120: struct timer_list removal; ! 121: socket_bind_t *bind; ! 122: } socket_info_t; ! 123: ! 124: #define SOCKET_PRESENT 0x01 ! 125: #define SOCKET_BUSY 0x02 ! 126: #define SOCKET_REMOVAL_PENDING 0x10 ! 127: ! 128: /*====================================================================*/ ! 129: ! 130: /* Device driver ID passed to Card Services */ ! 131: static dev_info_t dev_info = "Driver Services"; ! 132: ! 133: /* Linked list of all registered device drivers */ ! 134: static driver_info_t *root_driver = NULL; ! 135: ! 136: static int sockets = 0, major_dev = -1; ! 137: static socket_info_t *socket_table = NULL; ! 138: ! 139: extern struct proc_dir_entry *proc_pccard; ! 140: ! 141: /* We use this to distinguish in-kernel from modular drivers */ ! 142: static int init_status = 1; ! 143: ! 144: /*====================================================================*/ ! 145: ! 146: static void cs_error(client_handle_t handle, int func, int ret) ! 147: { ! 148: error_info_t err = { func, ret }; ! 149: CardServices(ReportError, handle, &err); ! 150: } ! 151: ! 152: /*====================================================================== ! 153: ! 154: Register_pccard_driver() and unregister_pccard_driver() are used ! 155: tell Driver Services that a PC Card client driver is available to ! 156: be bound to sockets. ! 157: ! 158: ======================================================================*/ ! 159: ! 160: int register_pccard_driver(dev_info_t *dev_info, ! 161: dev_link_t *(*attach)(void), ! 162: void (*detach)(dev_link_t *)) ! 163: { ! 164: driver_info_t *driver; ! 165: socket_bind_t *b; ! 166: int i; ! 167: ! 168: DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info); ! 169: for (driver = root_driver; driver; driver = driver->next) ! 170: if (strncmp((char *)dev_info, (char *)driver->dev_info, ! 171: DEV_NAME_LEN) == 0) ! 172: break; ! 173: if (!driver) { ! 174: driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); ! 175: if (!driver) return -ENOMEM; ! 176: strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN); ! 177: driver->use_count = 0; ! 178: driver->status = init_status; ! 179: driver->next = root_driver; ! 180: root_driver = driver; ! 181: } ! 182: ! 183: driver->attach = attach; ! 184: driver->detach = detach; ! 185: if (driver->use_count == 0) return 0; ! 186: ! 187: /* Instantiate any already-bound devices */ ! 188: for (i = 0; i < sockets; i++) ! 189: for (b = socket_table[i].bind; b; b = b->next) { ! 190: if (b->driver != driver) continue; ! 191: b->instance = driver->attach(); ! 192: if (b->instance == NULL) ! 193: printk(KERN_NOTICE "ds: unable to create instance " ! 194: "of '%s'!\n", driver->dev_info); ! 195: } ! 196: ! 197: return 0; ! 198: } /* register_pccard_driver */ ! 199: ! 200: /*====================================================================*/ ! 201: ! 202: int unregister_pccard_driver(dev_info_t *dev_info) ! 203: { ! 204: driver_info_t *target, **d = &root_driver; ! 205: socket_bind_t *b; ! 206: int i; ! 207: ! 208: DEBUG(0, "ds: unregister_pccard_driver('%s')\n", ! 209: (char *)dev_info); ! 210: while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info, ! 211: DEV_NAME_LEN) != 0)) ! 212: d = &(*d)->next; ! 213: if (*d == NULL) ! 214: return -ENODEV; ! 215: ! 216: target = *d; ! 217: if (target->use_count == 0) { ! 218: *d = target->next; ! 219: kfree(target); ! 220: } else { ! 221: /* Blank out any left-over device instances */ ! 222: target->attach = NULL; target->detach = NULL; ! 223: for (i = 0; i < sockets; i++) ! 224: for (b = socket_table[i].bind; b; b = b->next) ! 225: if (b->driver == target) b->instance = NULL; ! 226: } ! 227: return 0; ! 228: } /* unregister_pccard_driver */ ! 229: ! 230: /*====================================================================*/ ! 231: ! 232: #ifdef HAS_PROC_BUS ! 233: static int proc_read_drivers(char *buf, char **start, off_t pos, ! 234: int count, int *eof, void *data) ! 235: { ! 236: driver_info_t *d; ! 237: char *p = buf; ! 238: for (d = root_driver; d; d = d->next) ! 239: p += sprintf(p, "%-24.24s %d %d\n", d->dev_info, ! 240: d->status, d->use_count); ! 241: return (p - buf); ! 242: } ! 243: #endif ! 244: ! 245: /*====================================================================== ! 246: ! 247: These manage a ring buffer of events pending for one user process ! 248: ! 249: ======================================================================*/ ! 250: ! 251: static int queue_empty(user_info_t *user) ! 252: { ! 253: return (user->event_head == user->event_tail); ! 254: } ! 255: ! 256: static event_t get_queued_event(user_info_t *user) ! 257: { ! 258: user->event_tail = (user->event_tail+1) % MAX_EVENTS; ! 259: return user->event[user->event_tail]; ! 260: } ! 261: ! 262: static void queue_event(user_info_t *user, event_t event) ! 263: { ! 264: user->event_head = (user->event_head+1) % MAX_EVENTS; ! 265: if (user->event_head == user->event_tail) ! 266: user->event_tail = (user->event_tail+1) % MAX_EVENTS; ! 267: user->event[user->event_head] = event; ! 268: } ! 269: ! 270: static void handle_event(socket_info_t *s, event_t event) ! 271: { ! 272: user_info_t *user; ! 273: for (user = s->user; user; user = user->next) ! 274: queue_event(user, event); ! 275: wake_up_interruptible(&s->queue); ! 276: } ! 277: ! 278: static int handle_request(socket_info_t *s, event_t event) ! 279: { ! 280: if (s->req_pending != 0) ! 281: return CS_IN_USE; ! 282: if (s->state & SOCKET_BUSY) ! 283: s->req_pending = 1; ! 284: handle_event(s, event); ! 285: if (s->req_pending > 0) { ! 286: interruptible_sleep_on(&s->request); ! 287: if (signal_pending(current)) ! 288: return CS_IN_USE; ! 289: else ! 290: return s->req_result; ! 291: } ! 292: return CS_SUCCESS; ! 293: } ! 294: ! 295: static void handle_removal(u_long sn) ! 296: { ! 297: socket_info_t *s = &socket_table[sn]; ! 298: handle_event(s, CS_EVENT_CARD_REMOVAL); ! 299: s->state &= ~SOCKET_REMOVAL_PENDING; ! 300: } ! 301: ! 302: /*====================================================================== ! 303: ! 304: The card status event handler. ! 305: ! 306: ======================================================================*/ ! 307: ! 308: static int ds_event(event_t event, int priority, ! 309: event_callback_args_t *args) ! 310: { ! 311: socket_info_t *s; ! 312: int i; ! 313: ! 314: DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n", ! 315: event, priority, args->client_handle); ! 316: s = args->client_data; ! 317: i = s - socket_table; ! 318: ! 319: switch (event) { ! 320: ! 321: case CS_EVENT_CARD_REMOVAL: ! 322: s->state &= ~SOCKET_PRESENT; ! 323: if (!(s->state & SOCKET_REMOVAL_PENDING)) { ! 324: s->state |= SOCKET_REMOVAL_PENDING; ! 325: s->removal.expires = jiffies + HZ/10; ! 326: add_timer(&s->removal); ! 327: } ! 328: break; ! 329: ! 330: case CS_EVENT_CARD_INSERTION: ! 331: s->state |= SOCKET_PRESENT; ! 332: handle_event(s, event); ! 333: break; ! 334: ! 335: case CS_EVENT_EJECTION_REQUEST: ! 336: return handle_request(s, event); ! 337: break; ! 338: ! 339: default: ! 340: handle_event(s, event); ! 341: break; ! 342: } ! 343: ! 344: return 0; ! 345: } /* ds_event */ ! 346: ! 347: /*====================================================================== ! 348: ! 349: bind_mtd() connects a memory region with an MTD client. ! 350: ! 351: ======================================================================*/ ! 352: ! 353: static int bind_mtd(int i, mtd_info_t *mtd_info) ! 354: { ! 355: mtd_bind_t bind_req; ! 356: int ret; ! 357: ! 358: bind_req.dev_info = &mtd_info->dev_info; ! 359: bind_req.Attributes = mtd_info->Attributes; ! 360: bind_req.Socket = i; ! 361: bind_req.CardOffset = mtd_info->CardOffset; ! 362: ret = CardServices(BindMTD, &bind_req); ! 363: if (ret != CS_SUCCESS) { ! 364: cs_error(NULL, BindMTD, ret); ! 365: printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" ! 366: " offset 0x%x\n", ! 367: (char *)bind_req.dev_info, i, bind_req.CardOffset); ! 368: return -ENODEV; ! 369: } ! 370: return 0; ! 371: } /* bind_mtd */ ! 372: ! 373: /*====================================================================== ! 374: ! 375: bind_request() connects a socket to a particular client driver. ! 376: It looks up the specified device ID in the list of registered ! 377: drivers, binds it to the socket, and tries to create an instance ! 378: of the device. unbind_request() deletes a driver instance. ! 379: ! 380: ======================================================================*/ ! 381: ! 382: static int bind_request(int i, bind_info_t *bind_info) ! 383: { ! 384: struct driver_info_t *driver; ! 385: socket_bind_t *b; ! 386: bind_req_t bind_req; ! 387: socket_info_t *s = &socket_table[i]; ! 388: int ret; ! 389: ! 390: DEBUG(2, "bind_request(%d, '%s')\n", i, ! 391: (char *)bind_info->dev_info); ! 392: for (driver = root_driver; driver; driver = driver->next) ! 393: if (strcmp((char *)driver->dev_info, ! 394: (char *)bind_info->dev_info) == 0) ! 395: break; ! 396: if (driver == NULL) { ! 397: driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); ! 398: if (!driver) return -ENOMEM; ! 399: strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN); ! 400: driver->use_count = 0; ! 401: driver->next = root_driver; ! 402: driver->attach = NULL; driver->detach = NULL; ! 403: root_driver = driver; ! 404: } ! 405: ! 406: for (b = s->bind; b; b = b->next) ! 407: if ((driver == b->driver) && ! 408: (bind_info->function == b->function)) ! 409: break; ! 410: if (b != NULL) { ! 411: bind_info->instance = b->instance; ! 412: return -EBUSY; ! 413: } ! 414: b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); ! 415: if (!b) ! 416: return -ENOMEM; ! 417: ! 418: bind_req.Socket = i; ! 419: bind_req.Function = bind_info->function; ! 420: bind_req.dev_info = &driver->dev_info; ! 421: ret = CardServices(BindDevice, &bind_req); ! 422: if (ret != CS_SUCCESS) { ! 423: cs_error(NULL, BindDevice, ret); ! 424: printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", ! 425: (char *)dev_info, i); ! 426: kfree(b); ! 427: return -ENODEV; ! 428: } ! 429: ! 430: /* Add binding to list for this socket */ ! 431: driver->use_count++; ! 432: b->driver = driver; ! 433: b->function = bind_info->function; ! 434: b->instance = NULL; ! 435: b->next = s->bind; ! 436: s->bind = b; ! 437: ! 438: if (driver->attach) { ! 439: b->instance = driver->attach(); ! 440: if (b->instance == NULL) { ! 441: printk(KERN_NOTICE "ds: unable to create instance " ! 442: "of '%s'!\n", (char *)bind_info->dev_info); ! 443: return -ENODEV; ! 444: } ! 445: } ! 446: ! 447: return 0; ! 448: } /* bind_request */ ! 449: ! 450: /*====================================================================*/ ! 451: ! 452: static int get_device_info(int i, bind_info_t *bind_info, int first) ! 453: { ! 454: socket_info_t *s = &socket_table[i]; ! 455: socket_bind_t *b; ! 456: dev_node_t *node; ! 457: ! 458: for (b = s->bind; b; b = b->next) ! 459: if ((strcmp((char *)b->driver->dev_info, ! 460: (char *)bind_info->dev_info) == 0) && ! 461: (b->function == bind_info->function)) ! 462: break; ! 463: if (b == NULL) return -ENODEV; ! 464: if ((b->instance == NULL) || ! 465: (b->instance->state & DEV_CONFIG_PENDING)) ! 466: return -EAGAIN; ! 467: if (first) ! 468: node = b->instance->dev; ! 469: else ! 470: for (node = b->instance->dev; node; node = node->next) ! 471: if (node == bind_info->next) break; ! 472: if (node == NULL) return -ENODEV; ! 473: ! 474: strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN); ! 475: bind_info->name[DEV_NAME_LEN-1] = '\0'; ! 476: bind_info->major = node->major; ! 477: bind_info->minor = node->minor; ! 478: bind_info->next = node->next; ! 479: ! 480: return 0; ! 481: } /* get_device_info */ ! 482: ! 483: /*====================================================================*/ ! 484: ! 485: static int unbind_request(int i, bind_info_t *bind_info) ! 486: { ! 487: socket_info_t *s = &socket_table[i]; ! 488: socket_bind_t **b, *c; ! 489: ! 490: DEBUG(2, "unbind_request(%d, '%s')\n", i, ! 491: (char *)bind_info->dev_info); ! 492: for (b = &s->bind; *b; b = &(*b)->next) ! 493: if ((strcmp((char *)(*b)->driver->dev_info, ! 494: (char *)bind_info->dev_info) == 0) && ! 495: ((*b)->function == bind_info->function)) ! 496: break; ! 497: if (*b == NULL) ! 498: return -ENODEV; ! 499: ! 500: c = *b; ! 501: c->driver->use_count--; ! 502: if (c->driver->detach) { ! 503: if (c->instance) ! 504: c->driver->detach(c->instance); ! 505: } else { ! 506: if (c->driver->use_count == 0) { ! 507: driver_info_t **d; ! 508: for (d = &root_driver; *d; d = &((*d)->next)) ! 509: if (c->driver == *d) break; ! 510: *d = (*d)->next; ! 511: kfree(c->driver); ! 512: } ! 513: } ! 514: *b = c->next; ! 515: kfree(c); ! 516: ! 517: return 0; ! 518: } /* unbind_request */ ! 519: ! 520: /*====================================================================== ! 521: ! 522: The user-mode PC Card device interface ! 523: ! 524: ======================================================================*/ ! 525: ! 526: /* Disable all the ds filesystem operations. */ ! 527: #ifndef MACH ! 528: ! 529: static int ds_open(struct inode *inode, struct file *file) ! 530: { ! 531: socket_t i = MINOR(inode->i_rdev); ! 532: socket_info_t *s; ! 533: user_info_t *user; ! 534: ! 535: DEBUG(0, "ds_open(socket %d)\n", i); ! 536: if ((i >= sockets) || (sockets == 0)) ! 537: return -ENODEV; ! 538: s = &socket_table[i]; ! 539: if ((file->f_flags & O_ACCMODE) != O_RDONLY) { ! 540: if (s->state & SOCKET_BUSY) ! 541: return -EBUSY; ! 542: else ! 543: s->state |= SOCKET_BUSY; ! 544: } ! 545: ! 546: MOD_INC_USE_COUNT; ! 547: user = kmalloc(sizeof(user_info_t), GFP_KERNEL); ! 548: if (!user) { ! 549: MOD_DEC_USE_COUNT; ! 550: return -ENOMEM; ! 551: } ! 552: user->event_tail = user->event_head = 0; ! 553: user->next = s->user; ! 554: user->user_magic = USER_MAGIC; ! 555: s->user = user; ! 556: file->private_data = user; ! 557: ! 558: if (s->state & SOCKET_PRESENT) ! 559: queue_event(user, CS_EVENT_CARD_INSERTION); ! 560: return 0; ! 561: } /* ds_open */ ! 562: ! 563: /*====================================================================*/ ! 564: ! 565: static FS_RELEASE_T ds_release(struct inode *inode, struct file *file) ! 566: { ! 567: socket_t i = MINOR(inode->i_rdev); ! 568: socket_info_t *s; ! 569: user_info_t *user, **link; ! 570: ! 571: DEBUG(0, "ds_release(socket %d)\n", i); ! 572: if ((i >= sockets) || (sockets == 0)) ! 573: return (FS_RELEASE_T)0; ! 574: s = &socket_table[i]; ! 575: user = file->private_data; ! 576: if (CHECK_USER(user)) ! 577: return (FS_RELEASE_T)0; ! 578: ! 579: /* Unlink user data structure */ ! 580: if ((file->f_flags & O_ACCMODE) != O_RDONLY) ! 581: s->state &= ~SOCKET_BUSY; ! 582: file->private_data = NULL; ! 583: for (link = &s->user; *link; link = &(*link)->next) ! 584: if (*link == user) break; ! 585: if (link == NULL) ! 586: return (FS_RELEASE_T)0; ! 587: *link = user->next; ! 588: user->user_magic = 0; ! 589: kfree(user); ! 590: ! 591: MOD_DEC_USE_COUNT; ! 592: return (FS_RELEASE_T)0; ! 593: } /* ds_release */ ! 594: ! 595: /*====================================================================*/ ! 596: ! 597: static ssize_t ds_read FOPS(struct inode *inode, ! 598: struct file *file, char *buf, ! 599: size_t count, loff_t *ppos) ! 600: { ! 601: socket_t i = MINOR(F_INODE(file)->i_rdev); ! 602: socket_info_t *s; ! 603: user_info_t *user; ! 604: ! 605: DEBUG(2, "ds_read(socket %d)\n", i); ! 606: ! 607: if ((i >= sockets) || (sockets == 0)) ! 608: return -ENODEV; ! 609: if (count < 4) ! 610: return -EINVAL; ! 611: s = &socket_table[i]; ! 612: user = file->private_data; ! 613: if (CHECK_USER(user)) ! 614: return -EIO; ! 615: ! 616: if (queue_empty(user)) { ! 617: interruptible_sleep_on(&s->queue); ! 618: if (signal_pending(current)) ! 619: return -EINTR; ! 620: } ! 621: put_user(get_queued_event(user), (int *)buf); ! 622: return 4; ! 623: } /* ds_read */ ! 624: ! 625: /*====================================================================*/ ! 626: ! 627: static ssize_t ds_write FOPS(struct inode *inode, ! 628: struct file *file, const char *buf, ! 629: size_t count, loff_t *ppos) ! 630: { ! 631: socket_t i = MINOR(F_INODE(file)->i_rdev); ! 632: socket_info_t *s; ! 633: user_info_t *user; ! 634: ! 635: DEBUG(2, "ds_write(socket %d)\n", i); ! 636: ! 637: if ((i >= sockets) || (sockets == 0)) ! 638: return -ENODEV; ! 639: if (count != 4) ! 640: return -EINVAL; ! 641: if ((file->f_flags & O_ACCMODE) == O_RDONLY) ! 642: return -EBADF; ! 643: s = &socket_table[i]; ! 644: user = file->private_data; ! 645: if (CHECK_USER(user)) ! 646: return -EIO; ! 647: ! 648: if (s->req_pending) { ! 649: s->req_pending--; ! 650: get_user(s->req_result, (int *)buf); ! 651: if ((s->req_result != 0) || (s->req_pending == 0)) ! 652: wake_up_interruptible(&s->request); ! 653: } else ! 654: return -EIO; ! 655: ! 656: return 4; ! 657: } /* ds_write */ ! 658: ! 659: /*====================================================================*/ ! 660: ! 661: #if (LINUX_VERSION_CODE < VERSION(2,1,23)) ! 662: ! 663: static int ds_select(struct inode *inode, struct file *file, ! 664: int sel_type, select_table *wait) ! 665: { ! 666: socket_t i = MINOR(inode->i_rdev); ! 667: socket_info_t *s; ! 668: user_info_t *user; ! 669: ! 670: DEBUG(2, "ds_select(socket %d)\n", i); ! 671: ! 672: if ((i >= sockets) || (sockets == 0)) ! 673: return -ENODEV; ! 674: s = &socket_table[i]; ! 675: user = file->private_data; ! 676: if (CHECK_USER(user)) ! 677: return -EIO; ! 678: if (sel_type != SEL_IN) ! 679: return 0; ! 680: if (!queue_empty(user)) ! 681: return 1; ! 682: select_wait(&s->queue, wait); ! 683: return 0; ! 684: } /* ds_select */ ! 685: ! 686: #else ! 687: ! 688: static u_int ds_poll(struct file *file, poll_table *wait) ! 689: { ! 690: socket_t i = MINOR(F_INODE(file)->i_rdev); ! 691: socket_info_t *s; ! 692: user_info_t *user; ! 693: ! 694: DEBUG(2, "ds_poll(socket %d)\n", i); ! 695: ! 696: if ((i >= sockets) || (sockets == 0)) ! 697: return POLLERR; ! 698: s = &socket_table[i]; ! 699: user = file->private_data; ! 700: if (CHECK_USER(user)) ! 701: return POLLERR; ! 702: POLL_WAIT(file, &s->queue, wait); ! 703: if (!queue_empty(user)) ! 704: return POLLIN | POLLRDNORM; ! 705: return 0; ! 706: } /* ds_poll */ ! 707: ! 708: #endif ! 709: ! 710: /*====================================================================*/ ! 711: ! 712: #endif /* !defined(MACH) */ ! 713: ! 714: static int ds_ioctl(struct inode * inode, struct file * file, ! 715: u_int cmd, u_long arg) ! 716: { ! 717: socket_t i = MINOR(inode->i_rdev); ! 718: socket_info_t *s; ! 719: u_int size; ! 720: int ret, err; ! 721: ds_ioctl_arg_t buf; ! 722: ! 723: DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg); ! 724: ! 725: if ((i >= sockets) || (sockets == 0)) ! 726: return -ENODEV; ! 727: s = &socket_table[i]; ! 728: ! 729: size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; ! 730: if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; ! 731: ! 732: /* Permission check */ ! 733: if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) ! 734: return -EPERM; ! 735: ! 736: #ifndef MACH ! 737: if (cmd & IOC_IN) { ! 738: err = verify_area(VERIFY_READ, (char *)arg, size); ! 739: if (err) { ! 740: DEBUG(3, "ds_ioctl(): verify_read = %d\n", err); ! 741: return err; ! 742: } ! 743: } ! 744: if (cmd & IOC_OUT) { ! 745: err = verify_area(VERIFY_WRITE, (char *)arg, size); ! 746: if (err) { ! 747: DEBUG(3, "ds_ioctl(): verify_write = %d\n", err); ! 748: return err; ! 749: } ! 750: } ! 751: #endif ! 752: ! 753: err = ret = 0; ! 754: ! 755: #ifndef MACH ! 756: if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size); ! 757: #else ! 758: if (cmd & IOC_IN) memcpy((char *) &buf, (char *) arg, size); ! 759: #endif ! 760: ! 761: switch (cmd) { ! 762: case DS_ADJUST_RESOURCE_INFO: ! 763: ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust); ! 764: break; ! 765: case DS_GET_CARD_SERVICES_INFO: ! 766: ret = CardServices(GetCardServicesInfo, &buf.servinfo); ! 767: break; ! 768: case DS_GET_CONFIGURATION_INFO: ! 769: ret = CardServices(GetConfigurationInfo, s->handle, &buf.config); ! 770: break; ! 771: case DS_GET_FIRST_TUPLE: ! 772: ret = CardServices(GetFirstTuple, s->handle, &buf.tuple); ! 773: break; ! 774: case DS_GET_NEXT_TUPLE: ! 775: ret = CardServices(GetNextTuple, s->handle, &buf.tuple); ! 776: break; ! 777: case DS_GET_TUPLE_DATA: ! 778: buf.tuple.TupleData = buf.tuple_parse.data; ! 779: buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); ! 780: ret = CardServices(GetTupleData, s->handle, &buf.tuple); ! 781: break; ! 782: case DS_PARSE_TUPLE: ! 783: buf.tuple.TupleData = buf.tuple_parse.data; ! 784: ret = CardServices(ParseTuple, s->handle, &buf.tuple, ! 785: &buf.tuple_parse.parse); ! 786: break; ! 787: case DS_RESET_CARD: ! 788: ret = CardServices(ResetCard, s->handle, NULL); ! 789: break; ! 790: case DS_GET_STATUS: ! 791: ret = CardServices(GetStatus, s->handle, &buf.status); ! 792: break; ! 793: case DS_VALIDATE_CIS: ! 794: ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo); ! 795: break; ! 796: case DS_SUSPEND_CARD: ! 797: ret = CardServices(SuspendCard, s->handle, NULL); ! 798: break; ! 799: case DS_RESUME_CARD: ! 800: ret = CardServices(ResumeCard, s->handle, NULL); ! 801: break; ! 802: case DS_EJECT_CARD: ! 803: ret = CardServices(EjectCard, s->handle, NULL); ! 804: break; ! 805: case DS_INSERT_CARD: ! 806: ret = CardServices(InsertCard, s->handle, NULL); ! 807: break; ! 808: case DS_ACCESS_CONFIGURATION_REGISTER: ! 809: if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) ! 810: return -EPERM; ! 811: ret = CardServices(AccessConfigurationRegister, s->handle, ! 812: &buf.conf_reg); ! 813: break; ! 814: case DS_GET_FIRST_REGION: ! 815: ret = CardServices(GetFirstRegion, s->handle, &buf.region); ! 816: break; ! 817: case DS_GET_NEXT_REGION: ! 818: ret = CardServices(GetNextRegion, s->handle, &buf.region); ! 819: break; ! 820: case DS_GET_FIRST_WINDOW: ! 821: buf.win_info.handle = (window_handle_t)s->handle; ! 822: ret = CardServices(GetFirstWindow, &buf.win_info.handle, ! 823: &buf.win_info.window); ! 824: break; ! 825: case DS_GET_NEXT_WINDOW: ! 826: ret = CardServices(GetNextWindow, &buf.win_info.handle, ! 827: &buf.win_info.window); ! 828: break; ! 829: case DS_GET_MEM_PAGE: ! 830: ret = CardServices(GetMemPage, buf.win_info.handle, ! 831: &buf.win_info.map); ! 832: break; ! 833: case DS_REPLACE_CIS: ! 834: ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump); ! 835: break; ! 836: case DS_BIND_REQUEST: ! 837: if (!capable(CAP_SYS_ADMIN)) return -EPERM; ! 838: err = bind_request(i, &buf.bind_info); ! 839: break; ! 840: case DS_GET_DEVICE_INFO: ! 841: err = get_device_info(i, &buf.bind_info, 1); ! 842: break; ! 843: case DS_GET_NEXT_DEVICE: ! 844: err = get_device_info(i, &buf.bind_info, 0); ! 845: break; ! 846: case DS_UNBIND_REQUEST: ! 847: err = unbind_request(i, &buf.bind_info); ! 848: break; ! 849: case DS_BIND_MTD: ! 850: if (!capable(CAP_SYS_ADMIN)) return -EPERM; ! 851: err = bind_mtd(i, &buf.mtd_info); ! 852: break; ! 853: default: ! 854: err = -EINVAL; ! 855: } ! 856: ! 857: if ((err == 0) && (ret != CS_SUCCESS)) { ! 858: DEBUG(2, "ds_ioctl: ret = %d\n", ret); ! 859: switch (ret) { ! 860: case CS_BAD_SOCKET: case CS_NO_CARD: ! 861: err = -ENODEV; break; ! 862: case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: ! 863: case CS_BAD_TUPLE: ! 864: err = -EINVAL; break; ! 865: case CS_IN_USE: ! 866: err = -EBUSY; break; ! 867: case CS_OUT_OF_RESOURCE: ! 868: err = -ENOSPC; break; ! 869: case CS_NO_MORE_ITEMS: ! 870: err = -ENODATA; break; ! 871: case CS_UNSUPPORTED_FUNCTION: ! 872: err = -ENOSYS; break; ! 873: default: ! 874: err = -EIO; break; ! 875: } ! 876: } ! 877: ! 878: #ifndef MACH ! 879: if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size); ! 880: #else ! 881: if (cmd & IOC_OUT) memcpy((char *) arg, (char *) &buf, size); ! 882: #endif ! 883: ! 884: return err; ! 885: } /* ds_ioctl */ ! 886: ! 887: /*====================================================================*/ ! 888: ! 889: #ifndef MACH ! 890: ! 891: static struct file_operations ds_fops = { ! 892: open: ds_open, ! 893: release: ds_release, ! 894: ioctl: ds_ioctl, ! 895: read: ds_read, ! 896: write: ds_write, ! 897: #if (LINUX_VERSION_CODE < VERSION(2,1,23)) ! 898: select: ds_select ! 899: #else ! 900: poll: ds_poll ! 901: #endif ! 902: }; ! 903: ! 904: #if (LINUX_VERSION_CODE <= VERSION(2,1,17)) ! 905: ! 906: #undef CONFIG_MODVERSIONS ! 907: static struct symbol_table ds_symtab = { ! 908: #include <linux/symtab_begin.h> ! 909: #undef X ! 910: #define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) } ! 911: X(register_pccard_driver), ! 912: X(unregister_pccard_driver), ! 913: #include <linux/symtab_end.h> ! 914: }; ! 915: ! 916: #else ! 917: ! 918: EXPORT_SYMBOL(register_pccard_driver); ! 919: EXPORT_SYMBOL(unregister_pccard_driver); ! 920: ! 921: #endif ! 922: ! 923: #endif /* !defined(MACH) */ ! 924: ! 925: /*====================================================================*/ ! 926: ! 927: int __init init_pcmcia_ds(void) ! 928: { ! 929: client_reg_t client_reg; ! 930: servinfo_t serv; ! 931: bind_req_t bind; ! 932: socket_info_t *s; ! 933: int i, ret; ! 934: ! 935: DEBUG(0, "%s\n", version); ! 936: ! 937: CardServices(GetCardServicesInfo, &serv); ! 938: if (serv.Revision != CS_RELEASE_CODE) { ! 939: printk(KERN_NOTICE "ds: Card Services release does not match!\n"); ! 940: return -EINVAL; ! 941: } ! 942: if (serv.Count == 0) { ! 943: printk(KERN_NOTICE "ds: no socket drivers loaded!\n"); ! 944: return -1; ! 945: } ! 946: ! 947: sockets = serv.Count; ! 948: socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL); ! 949: if (!socket_table) return -1; ! 950: for (i = 0, s = socket_table; i < sockets; i++, s++) { ! 951: s->state = 0; ! 952: s->user = NULL; ! 953: s->req_pending = 0; ! 954: init_waitqueue_head(&s->queue); ! 955: init_waitqueue_head(&s->request); ! 956: s->handle = NULL; ! 957: init_timer(&s->removal); ! 958: s->removal.data = i; ! 959: s->removal.function = &handle_removal; ! 960: s->bind = NULL; ! 961: } ! 962: ! 963: /* Set up hotline to Card Services */ ! 964: client_reg.dev_info = bind.dev_info = &dev_info; ! 965: client_reg.Attributes = INFO_MASTER_CLIENT; ! 966: client_reg.EventMask = ! 967: CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ! 968: CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ! 969: CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | ! 970: CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ! 971: client_reg.event_handler = &ds_event; ! 972: client_reg.Version = 0x0210; ! 973: for (i = 0; i < sockets; i++) { ! 974: bind.Socket = i; ! 975: bind.Function = BIND_FN_ALL; ! 976: ret = CardServices(BindDevice, &bind); ! 977: if (ret != CS_SUCCESS) { ! 978: cs_error(NULL, BindDevice, ret); ! 979: break; ! 980: } ! 981: client_reg.event_callback_args.client_data = &socket_table[i]; ! 982: ret = CardServices(RegisterClient, &socket_table[i].handle, ! 983: &client_reg); ! 984: if (ret != CS_SUCCESS) { ! 985: cs_error(NULL, RegisterClient, ret); ! 986: break; ! 987: } ! 988: } ! 989: ! 990: #ifndef MACH ! 991: /* Set up character device for user mode clients */ ! 992: i = register_chrdev(0, "pcmcia", &ds_fops); ! 993: if (i == -EBUSY) ! 994: printk(KERN_NOTICE "unable to find a free device # for " ! 995: "Driver Services\n"); ! 996: else ! 997: major_dev = i; ! 998: register_symtab(&ds_symtab); ! 999: #endif ! 1000: ! 1001: #ifdef HAS_PROC_BUS ! 1002: if (proc_pccard) ! 1003: create_proc_read_entry("drivers", 0, proc_pccard, ! 1004: proc_read_drivers, NULL); ! 1005: init_status = 0; ! 1006: #endif ! 1007: return 0; ! 1008: } ! 1009: ! 1010: #ifdef MODULE ! 1011: ! 1012: int __init init_module(void) ! 1013: { ! 1014: return init_pcmcia_ds(); ! 1015: } ! 1016: ! 1017: void __exit cleanup_module(void) ! 1018: { ! 1019: int i; ! 1020: #ifdef HAS_PROC_BUS ! 1021: if (proc_pccard) ! 1022: remove_proc_entry("drivers", proc_pccard); ! 1023: #endif ! 1024: if (major_dev != -1) ! 1025: unregister_chrdev(major_dev, "pcmcia"); ! 1026: for (i = 0; i < sockets; i++) ! 1027: CardServices(DeregisterClient, socket_table[i].handle); ! 1028: sockets = 0; ! 1029: kfree(socket_table); ! 1030: } ! 1031: ! 1032: #endif ! 1033: ! 1034: /*====================================================================*/ ! 1035: ! 1036: /* Include the interface glue code to GNU Mach. */ ! 1037: #include "../glue/ds.c" ! 1038: ! 1039: /*====================================================================*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.