|
|
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, ¬ify);
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.