Annotation of Gnu-Mach/linux/pcmcia-cs/glue/ds.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * pcmcia-socket `device' driver
                      3:  *
                      4:  * Copyright (C) 2006, 2007 Free Software Foundation, Inc.
                      5:  * Written by Stefan Siegl <[email protected]>.
                      6:  *
                      7:  * This file is part of GNU Mach.
                      8:  *
                      9:  * This program is free software; you can redistribute it and/or modify
                     10:  * it under the terms of the GNU General Public License as published by
                     11:  * the Free Software Foundation; either version 2, or (at your option)
                     12:  * any later version.
                     13:  *
                     14:  * This program is distributed in the hope that it will be useful,
                     15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17:  * GNU General Public License for more details.
                     18:  *
                     19:  * You should have received a copy of the GNU General Public License
                     20:  * along with this program; if not, write to the Free Software
                     21:  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     22:  */
                     23: 
                     24: /* This file is included from linux/pcmcia-cs/modules/ds.c.  */
                     25: 
                     26: /*
                     27:  * This is really ugly.  But this is glue code, so...  It's about the `kfree'
                     28:  * symbols in <linux/malloc.h> and <kern/kalloc.h>.
                     29:  */
                     30: #undef kfree
                     31: 
                     32: /*
                     33:  * <kern/sched_prim.h> defines another event_t which is not used in this
                     34:  * file, so name it mach_event_t to avoid a clash.
                     35:  */
                     36: #define event_t mach_event_t
                     37: #include <kern/sched_prim.h>
                     38: #undef event_t
                     39: 
                     40: #include <mach/port.h>
                     41: #include <mach/notify.h>
                     42: #include <mach/mig_errors.h>
                     43: 
                     44: #include <ipc/ipc_port.h>
                     45: #include <ipc/ipc_space.h>
                     46: 
                     47: #include <device/device_types.h>
                     48: #include <device/device_port.h>
                     49: #include <device/io_req.h>
                     50: #include <device/ds_routines.h>
                     51: 
                     52: #include <device/device_emul.h>
                     53: 
                     54: #include <device/device_reply.user.h>
                     55: 
                     56: /* Eliminate the queue_empty macro from Mach header files.  */
                     57: #undef queue_empty
                     58: 
                     59: struct device_emulation_ops linux_pcmcia_emulation_ops;
                     60: 
                     61: /*
                     62:  * We have our very own device emulation stack because we need to carry a
                     63:  * pointer from the open call via read until the final close call: a
                     64:  * pointer to the user's event queue.
                     65:  */
                     66: struct mach_socket_device {
                     67:   /*
                     68:    * Pointer to the mach_device we have allocated.  This must be the
                     69:    * first entry in this struct, in order to be able to cast to
                     70:    * mach_device.
                     71:    */
                     72:   struct mach_device   mach_dev;
                     73: 
                     74:   /*
                     75:    * Pointer to the user info of pcmcia data services.
                     76:    */
                     77:   user_info_t          *user;
                     78: 
                     79:   /*
                     80:    * Cache for carrying data from set_status to get_status calls.  This
                     81:    * is needed for write ioctls.
                     82:    */
                     83:   ds_ioctl_arg_t       carry;
                     84: };
                     85: 
                     86: 
                     87: static void
                     88: ds_device_deallocate(void *p)
                     89: {
                     90:   mach_device_t device = (mach_device_t) p;
                     91: 
                     92:   simple_lock(&device->ref_lock);
                     93:   if (--device->ref_count > 0)
                     94:     {
                     95:       simple_unlock(&device->ref_lock);
                     96:       return;
                     97:     }
                     98: 
                     99:   simple_unlock(&device->ref_lock);
                    100:   
                    101:   /*
                    102:    * do what the original ds_release would do, ...
                    103:    */
                    104:   socket_t i = device->dev_number;
                    105:   socket_info_t *s;
                    106:   user_info_t *user, **link;
                    107: 
                    108:   s = &socket_table[i];
                    109:   user = ((struct mach_socket_device *) device)->user;
                    110: 
                    111:   /* allow to access the device again ... */
                    112:   if(device->flag & D_WRITE)
                    113:     s->state &= ~SOCKET_BUSY;
                    114: 
                    115:   /* Unlink user data structure */
                    116:   for (link = &s->user; *link; link = &(*link)->next)
                    117:     if (*link == user) break;
                    118: 
                    119:   if(link)
                    120:     {
                    121:       *link = user->next;
                    122:       user->user_magic = 0;
                    123:       linux_kfree(user);
                    124:     }
                    125: 
                    126:   /* now finally reap the device */
                    127:   linux_kfree(device);
                    128: }
                    129: 
                    130: /*
                    131:  * Return the send right associated with this socket device incarnation.
                    132:  */
                    133: static ipc_port_t
                    134: dev_to_port(void *d)
                    135: {
                    136:   struct mach_device *dev = d;
                    137: 
                    138:   if(! dev) 
                    139:     return IP_NULL;
                    140: 
                    141:   ipc_port_t port = ipc_port_make_send(dev->port);
                    142: 
                    143:   ds_device_deallocate(dev);
                    144:   return port;
                    145: }
                    146: 
                    147: 
                    148: static inline int
                    149: atoi(const char *ptr)
                    150: {
                    151:   if(! ptr) 
                    152:     return 0;
                    153: 
                    154:   int i = 0;
                    155:   while(*ptr >= '0' && *ptr <= '9')
                    156:     i = i * 10 + *(ptr ++) - '0';
                    157: 
                    158:   return i;
                    159: }
                    160: 
                    161: 
                    162: /*
                    163:  * Try to open the per-socket pseudo device `socket%d'.
                    164:  */
                    165: static io_return_t
                    166: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
                    167:             dev_mode_t mode, char *name, device_t *devp /* out */)
                    168: {
                    169:   if(! socket_table)
                    170:     return D_NO_SUCH_DEVICE;
                    171: 
                    172:   if(strlen(name) < 7 || strncmp(name, "socket", 6))
                    173:     return D_NO_SUCH_DEVICE;
                    174: 
                    175:   socket_t i = atoi(name + 6);
                    176:   if(i >= MAX_SOCKS || i >= sockets)
                    177:     return D_NO_SUCH_DEVICE;
                    178: 
                    179:   io_return_t err = D_SUCCESS;
                    180: 
                    181:   struct mach_device *dev;
                    182:   dev = linux_kmalloc(sizeof(struct mach_socket_device), GFP_KERNEL);
                    183:   if(! dev)
                    184:     {
                    185:       err = D_NO_MEMORY;
                    186:       goto out;
                    187:     }
                    188: 
                    189:   memset(dev, 0, sizeof(struct mach_socket_device));
                    190:   mach_device_reference(dev);
                    191: 
                    192:   /* now do, what ds_open would do if it would be in charge */
                    193:   socket_info_t *s = &socket_table[i];
                    194: 
                    195:   if(mode & D_WRITE)
                    196:     {
                    197:       if(s->state & SOCKET_BUSY)
                    198:        {
                    199:          err = D_ALREADY_OPEN;
                    200:          goto out;
                    201:        }
                    202:       else
                    203:        s->state |= SOCKET_BUSY;
                    204:     }
                    205: 
                    206:   user_info_t *user = linux_kmalloc(sizeof(user_info_t), GFP_KERNEL);
                    207:   if(! user) 
                    208:     {
                    209:       err = D_NO_MEMORY;
                    210:       goto out;
                    211:     }
                    212: 
                    213:   user->event_tail = user->event_head = 0;
                    214:   user->next = s->user;
                    215:   user->user_magic = USER_MAGIC;
                    216:   s->user = user;
                    217: 
                    218:   ((struct mach_socket_device *) dev)->user = user;
                    219: 
                    220:   if(s->state & SOCKET_PRESENT)
                    221:     queue_event(user, CS_EVENT_CARD_INSERTION);
                    222: 
                    223:   /* just set up the rest of our mach_device now ... */
                    224:   dev->dev.emul_ops = &linux_pcmcia_emulation_ops;
                    225:   dev->dev.emul_data = dev;
                    226: 
                    227:   dev->dev_number = i;
                    228:   dev->flag = mode;
                    229: 
                    230:   dev->port = ipc_port_alloc_kernel();
                    231:   if(dev->port == IP_NULL)
                    232:     {
                    233:       err = KERN_RESOURCE_SHORTAGE;
                    234:       goto out;
                    235:     }
                    236: 
                    237:   mach_device_reference(dev);
                    238:   ipc_kobject_set(dev->port, (ipc_kobject_t) &dev->dev, IKOT_DEVICE);
                    239: 
                    240:   /* request no-senders notifications on device port */
                    241:   ipc_port_t notify = ipc_port_make_sonce(dev->port);
                    242:   ip_lock(dev->port);
                    243:   ipc_port_nsrequest(dev->port, 1, notify, &notify);
                    244:   assert (notify == IP_NULL);
                    245: 
                    246:  out:
                    247:   if(err)
                    248:     {
                    249:       if(dev)
                    250:        {
                    251:          if(dev->port != IP_NULL)
                    252:            {
                    253:              ipc_kobject_set(dev->port, IKO_NULL, IKOT_NONE);
                    254:              ipc_port_dealloc_kernel(dev->port);
                    255:            }
                    256: 
                    257:          linux_kfree(dev);
                    258:          dev = NULL;
                    259:        }
                    260:     }
                    261:   else
                    262:     dev->state = DEV_STATE_OPEN;
                    263: 
                    264:   *devp = &dev->dev;
                    265: 
                    266:   if (IP_VALID (reply_port))
                    267:     ds_device_open_reply(reply_port, reply_port_type,
                    268:                         err, dev_to_port(dev));
                    269:   return MIG_NO_REPLY;
                    270: }
                    271: 
                    272: 
                    273: /*
                    274:  * Close the device DEV.
                    275:  */
                    276: static int
                    277: device_close (void *devp)
                    278: {
                    279:   struct mach_device *dev = (struct mach_device *) devp;
                    280: 
                    281:   dev->state = DEV_STATE_CLOSING;
                    282: 
                    283:   /* check whether there is a blocked read request pending,
                    284:    * in that case, abort that one before closing 
                    285:    */
                    286:   while(dev->ref_count > 2)
                    287:     {
                    288:       socket_t i = dev->dev_number;
                    289:       socket_info_t *s = &socket_table[i];
                    290:       wake_up_interruptible(&s->queue);
                    291:       
                    292:       /* wait for device_read to exit */
                    293:       return D_INVALID_OPERATION;
                    294:     }
                    295: 
                    296:   dev_port_remove(dev);
                    297:   ipc_port_dealloc_kernel(dev->port);
                    298: 
                    299:   return 0;
                    300: }
                    301: 
                    302: static io_return_t
                    303: device_read(void *d, ipc_port_t reply_port,
                    304:            mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    305:            recnum_t recnum, int bytes_wanted,
                    306:            io_buf_ptr_t *data, unsigned int *data_count)
                    307: {
                    308:   struct mach_device *dev = (struct mach_device *) d;
                    309: 
                    310:   if(dev->state != DEV_STATE_OPEN)
                    311:     return D_NO_SUCH_DEVICE;
                    312: 
                    313:   if(! IP_VALID(reply_port)) {
                    314:     printk(KERN_INFO "ds: device_read: invalid reply port.\n");
                    315:     return (MIG_NO_REPLY);      /* no sense in doing anything */
                    316:   }
                    317: 
                    318:   /* prepare an io request structure */
                    319:   io_req_t ior;
                    320:   io_req_alloc(ior, 0);
                    321: 
                    322:   ior->io_device = dev;
                    323:   ior->io_unit = dev->dev_number;
                    324:   ior->io_op = IO_READ | IO_CALL;
                    325:   ior->io_mode = mode;
                    326:   ior->io_recnum = recnum;
                    327:   ior->io_data = 0;
                    328:   ior->io_count        = bytes_wanted;
                    329:   ior->io_alloc_size = 0;
                    330:   ior->io_residual = 0;
                    331:   ior->io_error = 0;
                    332:   ior->io_done = ds_read_done;
                    333:   ior->io_reply_port = reply_port;
                    334:   ior->io_reply_port_type = reply_port_type;
                    335: 
                    336:   /*
                    337:    * The ior keeps an extra reference for the device.
                    338:    */
                    339:   mach_device_reference(dev);
                    340: 
                    341:   /* do the read finally */
                    342:   io_return_t result = D_SUCCESS;
                    343:   
                    344:   result = device_read_alloc(ior, ior->io_count);
                    345:   if(result != KERN_SUCCESS)
                    346:     goto out;
                    347: 
                    348:   socket_t i = dev->dev_number;
                    349:   socket_info_t *s = &socket_table[i];
                    350:   user_info_t *user = ((struct mach_socket_device *) dev)->user;
                    351: 
                    352:   if(ior->io_count < 4)
                    353:     return D_INVALID_SIZE;
                    354: 
                    355:   if(CHECK_USER(user))
                    356:     {
                    357:       result = D_IO_ERROR;
                    358:       goto out;
                    359:     }
                    360: 
                    361:   while(queue_empty(user))
                    362:     {
                    363:       if(ior->io_mode & D_NOWAIT)
                    364:        {
                    365:          result = D_WOULD_BLOCK;
                    366:          goto out;
                    367:        }
                    368:       else
                    369:        interruptible_sleep_on(&s->queue);
                    370:    
                    371:       if(dev->state == DEV_STATE_CLOSING)
                    372:        {
                    373:          result = D_DEVICE_DOWN;
                    374:          goto out;
                    375:        }
                    376:     }
                    377:   
                    378:   event_t ev = get_queued_event(user);
                    379:   memcpy(ior->io_data, &ev, sizeof(event_t));
                    380: 
                    381:   ior->io_residual = ior->io_count - sizeof(event_t);
                    382:   
                    383:  out:
                    384:   /*
                    385:    * Return result via ds_read_done.
                    386:    */
                    387:   ior->io_error = result;
                    388:   (void) ds_read_done(ior);
                    389:   io_req_free(ior);
                    390: 
                    391:   return (MIG_NO_REPLY);       /* reply has already been sent. */
                    392: }
                    393: 
                    394: 
                    395: static io_return_t
                    396: device_set_status(void *d, dev_flavor_t req, dev_status_t arg,
                    397:                  mach_msg_type_number_t sz)
                    398: {
                    399:   struct mach_socket_device *dev = (struct mach_socket_device *) d;
                    400: 
                    401:   if(sz * sizeof(int) > sizeof(ds_ioctl_arg_t))
                    402:     return D_INVALID_OPERATION;
                    403: 
                    404:   if(dev->mach_dev.state != DEV_STATE_OPEN)
                    405:     return D_NO_SUCH_DEVICE;
                    406: 
                    407:   unsigned int ioctl_sz = (req & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
                    408:   memcpy(&dev->carry, arg, ioctl_sz);
                    409: 
                    410:   return D_SUCCESS;
                    411: }
                    412: 
                    413: static io_return_t
                    414: device_get_status(void *d, dev_flavor_t req, dev_status_t arg,
                    415:                  mach_msg_type_number_t *sz)
                    416: {
                    417:   struct mach_socket_device *dev = (struct mach_socket_device *) d;
                    418: 
                    419:   if(dev->mach_dev.state != DEV_STATE_OPEN)
                    420:     return D_NO_SUCH_DEVICE;
                    421: 
                    422:   struct inode inode;
                    423:   inode.i_rdev = dev->mach_dev.dev_number;
                    424:   int ret = ds_ioctl(&inode, NULL, req, (u_long) &dev->carry);
                    425: 
                    426:   if(ret)
                    427:     return D_IO_ERROR;
                    428: 
                    429:   unsigned int ioctl_sz = (req & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
                    430:   if(req & IOC_OUT) memcpy(arg, &dev->carry, ioctl_sz);
                    431: 
                    432:   return D_SUCCESS;
                    433: }
                    434: 
                    435: 
                    436: struct device_emulation_ops linux_pcmcia_emulation_ops =
                    437:   {
                    438:     (void*) mach_device_reference,
                    439:     ds_device_deallocate,
                    440:     dev_to_port,
                    441:     device_open,
                    442:     device_close,
                    443:     NULL, /* device_write */
                    444:     NULL, /* write_inband */
                    445:     device_read,
                    446:     NULL, /* read_inband */
                    447:     device_set_status,
                    448:     device_get_status,
                    449:     NULL, /* set_filter */
                    450:     NULL, /* map */
                    451:     NULL, /* no_senders */
                    452:     NULL, /* write_trap */
                    453:     NULL /* writev_trap */
                    454:   };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.