Annotation of Gnu-Mach/linux/pcmcia-cs/glue/ds.c, revision 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.