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