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

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

unix.superglobalmegacorp.com

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