Merge /spare/repo/netdev-2.6 branch 'ieee80211'
[deliverable/linux.git] / drivers / pcmcia / pcmcia_ioctl.c
1 /*
2 * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
13 * (C) 2003 - 2004 Dominik Brodowski
14 */
15
16 /*
17 * This file will go away soon.
18 */
19
20
21 #include <linux/config.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/major.h>
26 #include <linux/errno.h>
27 #include <linux/ioctl.h>
28 #include <linux/proc_fs.h>
29 #include <linux/poll.h>
30 #include <linux/pci.h>
31 #include <linux/workqueue.h>
32
33 #define IN_CARD_SERVICES
34 #include <pcmcia/cs_types.h>
35 #include <pcmcia/cs.h>
36 #include <pcmcia/cistpl.h>
37 #include <pcmcia/ds.h>
38 #include <pcmcia/ss.h>
39
40 #include "cs_internal.h"
41 #include "ds_internal.h"
42
43 static int major_dev = -1;
44
45
46 /* Device user information */
47 #define MAX_EVENTS 32
48 #define USER_MAGIC 0x7ea4
49 #define CHECK_USER(u) \
50 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
51
52 typedef struct user_info_t {
53 u_int user_magic;
54 int event_head, event_tail;
55 event_t event[MAX_EVENTS];
56 struct user_info_t *next;
57 struct pcmcia_socket *socket;
58 } user_info_t;
59
60
61 #ifdef DEBUG
62 extern int ds_pc_debug;
63 #define cs_socket_name(skt) ((skt)->dev.class_id)
64
65 #define ds_dbg(lvl, fmt, arg...) do { \
66 if (ds_pc_debug >= lvl) \
67 printk(KERN_DEBUG "ds: " fmt , ## arg); \
68 } while (0)
69 #else
70 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
71 #endif
72
73
74 /* backwards-compatible accessing of driver --- by name! */
75
76 static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
77 {
78 struct device_driver *drv;
79 struct pcmcia_driver *p_drv;
80
81 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
82 if (!drv)
83 return NULL;
84
85 p_drv = container_of(drv, struct pcmcia_driver, drv);
86
87 return (p_drv);
88 }
89
90
91 #ifdef CONFIG_PROC_FS
92 static struct proc_dir_entry *proc_pccard = NULL;
93
94 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
95 {
96 char **p = d;
97 struct pcmcia_driver *p_drv = container_of(driver,
98 struct pcmcia_driver, drv);
99
100 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
101 #ifdef CONFIG_MODULE_UNLOAD
102 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
103 #else
104 1
105 #endif
106 );
107 d = (void *) p;
108
109 return 0;
110 }
111
112 static int proc_read_drivers(char *buf, char **start, off_t pos,
113 int count, int *eof, void *data)
114 {
115 char *p = buf;
116
117 bus_for_each_drv(&pcmcia_bus_type, NULL,
118 (void *) &p, proc_read_drivers_callback);
119
120 return (p - buf);
121 }
122 #endif
123
124 /*======================================================================
125
126 These manage a ring buffer of events pending for one user process
127
128 ======================================================================*/
129
130
131 static int queue_empty(user_info_t *user)
132 {
133 return (user->event_head == user->event_tail);
134 }
135
136 static event_t get_queued_event(user_info_t *user)
137 {
138 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
139 return user->event[user->event_tail];
140 }
141
142 static void queue_event(user_info_t *user, event_t event)
143 {
144 user->event_head = (user->event_head+1) % MAX_EVENTS;
145 if (user->event_head == user->event_tail)
146 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
147 user->event[user->event_head] = event;
148 }
149
150 void handle_event(struct pcmcia_socket *s, event_t event)
151 {
152 user_info_t *user;
153 for (user = s->user; user; user = user->next)
154 queue_event(user, event);
155 wake_up_interruptible(&s->queue);
156 }
157
158
159 /*======================================================================
160
161 bind_request() and bind_device() are merged by now. Register_client()
162 is called right at the end of bind_request(), during the driver's
163 ->attach() call. Individual descriptions:
164
165 bind_request() connects a socket to a particular client driver.
166 It looks up the specified device ID in the list of registered
167 drivers, binds it to the socket, and tries to create an instance
168 of the device. unbind_request() deletes a driver instance.
169
170 Bind_device() associates a device driver with a particular socket.
171 It is normally called by Driver Services after it has identified
172 a newly inserted card. An instance of that driver will then be
173 eligible to register as a client of this socket.
174
175 Register_client() uses the dev_info_t handle to match the
176 caller with a socket. The driver must have already been bound
177 to a socket with bind_device() -- in fact, bind_device()
178 allocates the client structure that will be used.
179
180 ======================================================================*/
181
182 static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
183 {
184 struct pcmcia_driver *p_drv;
185 struct pcmcia_device *p_dev;
186 int ret = 0;
187 unsigned long flags;
188
189 s = pcmcia_get_socket(s);
190 if (!s)
191 return -EINVAL;
192
193 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
194 (char *)bind_info->dev_info);
195
196 p_drv = get_pcmcia_driver(&bind_info->dev_info);
197 if (!p_drv) {
198 ret = -EINVAL;
199 goto err_put;
200 }
201
202 if (!try_module_get(p_drv->owner)) {
203 ret = -EINVAL;
204 goto err_put_driver;
205 }
206
207 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
208 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
209 if (p_dev->func == bind_info->function) {
210 if ((p_dev->dev.driver == &p_drv->drv)) {
211 if (p_dev->cardmgr) {
212 /* if there's already a device
213 * registered, and it was registered
214 * by userspace before, we need to
215 * return the "instance". */
216 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
217 bind_info->instance = p_dev->instance;
218 ret = -EBUSY;
219 goto err_put_module;
220 } else {
221 /* the correct driver managed to bind
222 * itself magically to the correct
223 * device. */
224 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
225 p_dev->cardmgr = p_drv;
226 ret = 0;
227 goto err_put_module;
228 }
229 } else if (!p_dev->dev.driver) {
230 /* there's already a device available where
231 * no device has been bound to yet. So we don't
232 * need to register a device! */
233 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
234 goto rescan;
235 }
236 }
237 }
238 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
239
240 p_dev = pcmcia_device_add(s, bind_info->function);
241 if (!p_dev) {
242 ret = -EIO;
243 goto err_put_module;
244 }
245
246 rescan:
247 p_dev->cardmgr = p_drv;
248
249 /* if a driver is already running, we can abort */
250 if (p_dev->dev.driver)
251 goto err_put_module;
252
253 /*
254 * Prevent this racing with a card insertion.
255 */
256 down(&s->skt_sem);
257 bus_rescan_devices(&pcmcia_bus_type);
258 up(&s->skt_sem);
259
260 /* check whether the driver indeed matched. I don't care if this
261 * is racy or not, because it can only happen on cardmgr access
262 * paths...
263 */
264 if (!(p_dev->dev.driver == &p_drv->drv))
265 p_dev->cardmgr = NULL;
266
267 err_put_module:
268 module_put(p_drv->owner);
269 err_put_driver:
270 put_driver(&p_drv->drv);
271 err_put:
272 pcmcia_put_socket(s);
273
274 return (ret);
275 } /* bind_request */
276
277 #ifdef CONFIG_CARDBUS
278
279 static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
280 {
281 if (!s || !(s->state & SOCKET_CARDBUS))
282 return NULL;
283
284 return s->cb_dev->subordinate;
285 }
286 #endif
287
288 static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
289 {
290 dev_node_t *node;
291 struct pcmcia_device *p_dev;
292 unsigned long flags;
293 int ret = 0;
294
295 #ifdef CONFIG_CARDBUS
296 /*
297 * Some unbelievably ugly code to associate the PCI cardbus
298 * device and its driver with the PCMCIA "bind" information.
299 */
300 {
301 struct pci_bus *bus;
302
303 bus = pcmcia_lookup_bus(s);
304 if (bus) {
305 struct list_head *list;
306 struct pci_dev *dev = NULL;
307
308 list = bus->devices.next;
309 while (list != &bus->devices) {
310 struct pci_dev *pdev = pci_dev_b(list);
311 list = list->next;
312
313 if (first) {
314 dev = pdev;
315 break;
316 }
317
318 /* Try to handle "next" here some way? */
319 }
320 if (dev && dev->driver) {
321 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
322 bind_info->major = 0;
323 bind_info->minor = 0;
324 bind_info->next = NULL;
325 return 0;
326 }
327 }
328 }
329 #endif
330
331 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
332 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
333 if (p_dev->func == bind_info->function) {
334 p_dev = pcmcia_get_dev(p_dev);
335 if (!p_dev)
336 continue;
337 goto found;
338 }
339 }
340 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
341 return -ENODEV;
342
343 found:
344 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
345
346 if ((!p_dev->instance) ||
347 (p_dev->instance->state & DEV_CONFIG_PENDING)) {
348 ret = -EAGAIN;
349 goto err_put;
350 }
351
352 if (first)
353 node = p_dev->instance->dev;
354 else
355 for (node = p_dev->instance->dev; node; node = node->next)
356 if (node == bind_info->next)
357 break;
358 if (!node) {
359 ret = -ENODEV;
360 goto err_put;
361 }
362
363 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
364 bind_info->major = node->major;
365 bind_info->minor = node->minor;
366 bind_info->next = node->next;
367
368 err_put:
369 pcmcia_put_dev(p_dev);
370 return (ret);
371 } /* get_device_info */
372
373
374 static int ds_open(struct inode *inode, struct file *file)
375 {
376 socket_t i = iminor(inode);
377 struct pcmcia_socket *s;
378 user_info_t *user;
379
380 ds_dbg(0, "ds_open(socket %d)\n", i);
381
382 s = pcmcia_get_socket_by_nr(i);
383 if (!s)
384 return -ENODEV;
385 s = pcmcia_get_socket(s);
386 if (!s)
387 return -ENODEV;
388
389 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
390 if (s->pcmcia_state.busy) {
391 pcmcia_put_socket(s);
392 return -EBUSY;
393 }
394 else
395 s->pcmcia_state.busy = 1;
396 }
397
398 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
399 if (!user) {
400 pcmcia_put_socket(s);
401 return -ENOMEM;
402 }
403 user->event_tail = user->event_head = 0;
404 user->next = s->user;
405 user->user_magic = USER_MAGIC;
406 user->socket = s;
407 s->user = user;
408 file->private_data = user;
409
410 if (s->pcmcia_state.present)
411 queue_event(user, CS_EVENT_CARD_INSERTION);
412 return 0;
413 } /* ds_open */
414
415 /*====================================================================*/
416
417 static int ds_release(struct inode *inode, struct file *file)
418 {
419 struct pcmcia_socket *s;
420 user_info_t *user, **link;
421
422 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
423
424 user = file->private_data;
425 if (CHECK_USER(user))
426 goto out;
427
428 s = user->socket;
429
430 /* Unlink user data structure */
431 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
432 s->pcmcia_state.busy = 0;
433 }
434 file->private_data = NULL;
435 for (link = &s->user; *link; link = &(*link)->next)
436 if (*link == user) break;
437 if (link == NULL)
438 goto out;
439 *link = user->next;
440 user->user_magic = 0;
441 kfree(user);
442 pcmcia_put_socket(s);
443 out:
444 return 0;
445 } /* ds_release */
446
447 /*====================================================================*/
448
449 static ssize_t ds_read(struct file *file, char __user *buf,
450 size_t count, loff_t *ppos)
451 {
452 struct pcmcia_socket *s;
453 user_info_t *user;
454 int ret;
455
456 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
457
458 if (count < 4)
459 return -EINVAL;
460
461 user = file->private_data;
462 if (CHECK_USER(user))
463 return -EIO;
464
465 s = user->socket;
466 if (s->pcmcia_state.dead)
467 return -EIO;
468
469 ret = wait_event_interruptible(s->queue, !queue_empty(user));
470 if (ret == 0)
471 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
472
473 return ret;
474 } /* ds_read */
475
476 /*====================================================================*/
477
478 static ssize_t ds_write(struct file *file, const char __user *buf,
479 size_t count, loff_t *ppos)
480 {
481 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
482
483 if (count != 4)
484 return -EINVAL;
485 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
486 return -EBADF;
487
488 return -EIO;
489 } /* ds_write */
490
491 /*====================================================================*/
492
493 /* No kernel lock - fine */
494 static u_int ds_poll(struct file *file, poll_table *wait)
495 {
496 struct pcmcia_socket *s;
497 user_info_t *user;
498
499 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
500
501 user = file->private_data;
502 if (CHECK_USER(user))
503 return POLLERR;
504 s = user->socket;
505 /*
506 * We don't check for a dead socket here since that
507 * will send cardmgr into an endless spin.
508 */
509 poll_wait(file, &s->queue, wait);
510 if (!queue_empty(user))
511 return POLLIN | POLLRDNORM;
512 return 0;
513 } /* ds_poll */
514
515 /*====================================================================*/
516
517 extern int pcmcia_adjust_resource_info(adjust_t *adj);
518
519 static int ds_ioctl(struct inode * inode, struct file * file,
520 u_int cmd, u_long arg)
521 {
522 struct pcmcia_socket *s;
523 void __user *uarg = (char __user *)arg;
524 u_int size;
525 int ret, err;
526 ds_ioctl_arg_t *buf;
527 user_info_t *user;
528
529 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
530
531 user = file->private_data;
532 if (CHECK_USER(user))
533 return -EIO;
534
535 s = user->socket;
536 if (s->pcmcia_state.dead)
537 return -EIO;
538
539 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
540 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
541
542 /* Permission check */
543 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
544 return -EPERM;
545
546 if (cmd & IOC_IN) {
547 if (!access_ok(VERIFY_READ, uarg, size)) {
548 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
549 return -EFAULT;
550 }
551 }
552 if (cmd & IOC_OUT) {
553 if (!access_ok(VERIFY_WRITE, uarg, size)) {
554 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
555 return -EFAULT;
556 }
557 }
558 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
559 if (!buf)
560 return -ENOMEM;
561
562 err = ret = 0;
563
564 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
565
566 switch (cmd) {
567 case DS_ADJUST_RESOURCE_INFO:
568 ret = pcmcia_adjust_resource_info(&buf->adjust);
569 break;
570 case DS_GET_CONFIGURATION_INFO:
571 if (buf->config.Function &&
572 (buf->config.Function >= s->functions))
573 ret = CS_BAD_ARGS;
574 else
575 ret = pccard_get_configuration_info(s,
576 buf->config.Function, &buf->config);
577 break;
578 case DS_GET_FIRST_TUPLE:
579 down(&s->skt_sem);
580 pcmcia_validate_mem(s);
581 up(&s->skt_sem);
582 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
583 break;
584 case DS_GET_NEXT_TUPLE:
585 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
586 break;
587 case DS_GET_TUPLE_DATA:
588 buf->tuple.TupleData = buf->tuple_parse.data;
589 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
590 ret = pccard_get_tuple_data(s, &buf->tuple);
591 break;
592 case DS_PARSE_TUPLE:
593 buf->tuple.TupleData = buf->tuple_parse.data;
594 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
595 break;
596 case DS_RESET_CARD:
597 ret = pccard_reset_card(s);
598 break;
599 case DS_GET_STATUS:
600 if (buf->status.Function &&
601 (buf->status.Function >= s->functions))
602 ret = CS_BAD_ARGS;
603 else
604 ret = pccard_get_status(s, buf->status.Function, &buf->status);
605 break;
606 case DS_VALIDATE_CIS:
607 down(&s->skt_sem);
608 pcmcia_validate_mem(s);
609 up(&s->skt_sem);
610 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
611 break;
612 case DS_SUSPEND_CARD:
613 ret = pcmcia_suspend_card(s);
614 break;
615 case DS_RESUME_CARD:
616 ret = pcmcia_resume_card(s);
617 break;
618 case DS_EJECT_CARD:
619 err = pcmcia_eject_card(s);
620 break;
621 case DS_INSERT_CARD:
622 err = pcmcia_insert_card(s);
623 break;
624 case DS_ACCESS_CONFIGURATION_REGISTER:
625 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
626 err = -EPERM;
627 goto free_out;
628 }
629 if (buf->conf_reg.Function &&
630 (buf->conf_reg.Function >= s->functions))
631 ret = CS_BAD_ARGS;
632 else
633 ret = pccard_access_configuration_register(s,
634 buf->conf_reg.Function, &buf->conf_reg);
635 break;
636 case DS_GET_FIRST_REGION:
637 case DS_GET_NEXT_REGION:
638 case DS_BIND_MTD:
639 if (!capable(CAP_SYS_ADMIN)) {
640 err = -EPERM;
641 goto free_out;
642 } else {
643 static int printed = 0;
644 if (!printed) {
645 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
646 printk(KERN_WARNING "MTD handling any more.\n");
647 printed++;
648 }
649 }
650 err = -EINVAL;
651 goto free_out;
652 break;
653 case DS_GET_FIRST_WINDOW:
654 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
655 &buf->win_info.window);
656 break;
657 case DS_GET_NEXT_WINDOW:
658 ret = pcmcia_get_window(s, &buf->win_info.handle,
659 buf->win_info.handle->index + 1, &buf->win_info.window);
660 break;
661 case DS_GET_MEM_PAGE:
662 ret = pcmcia_get_mem_page(buf->win_info.handle,
663 &buf->win_info.map);
664 break;
665 case DS_REPLACE_CIS:
666 ret = pcmcia_replace_cis(s, &buf->cisdump);
667 break;
668 case DS_BIND_REQUEST:
669 if (!capable(CAP_SYS_ADMIN)) {
670 err = -EPERM;
671 goto free_out;
672 }
673 err = bind_request(s, &buf->bind_info);
674 break;
675 case DS_GET_DEVICE_INFO:
676 err = get_device_info(s, &buf->bind_info, 1);
677 break;
678 case DS_GET_NEXT_DEVICE:
679 err = get_device_info(s, &buf->bind_info, 0);
680 break;
681 case DS_UNBIND_REQUEST:
682 err = 0;
683 break;
684 default:
685 err = -EINVAL;
686 }
687
688 if ((err == 0) && (ret != CS_SUCCESS)) {
689 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
690 switch (ret) {
691 case CS_BAD_SOCKET: case CS_NO_CARD:
692 err = -ENODEV; break;
693 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
694 case CS_BAD_TUPLE:
695 err = -EINVAL; break;
696 case CS_IN_USE:
697 err = -EBUSY; break;
698 case CS_OUT_OF_RESOURCE:
699 err = -ENOSPC; break;
700 case CS_NO_MORE_ITEMS:
701 err = -ENODATA; break;
702 case CS_UNSUPPORTED_FUNCTION:
703 err = -ENOSYS; break;
704 default:
705 err = -EIO; break;
706 }
707 }
708
709 if (cmd & IOC_OUT) {
710 if (__copy_to_user(uarg, (char *)buf, size))
711 err = -EFAULT;
712 }
713
714 free_out:
715 kfree(buf);
716 return err;
717 } /* ds_ioctl */
718
719 /*====================================================================*/
720
721 static struct file_operations ds_fops = {
722 .owner = THIS_MODULE,
723 .open = ds_open,
724 .release = ds_release,
725 .ioctl = ds_ioctl,
726 .read = ds_read,
727 .write = ds_write,
728 .poll = ds_poll,
729 };
730
731 void __init pcmcia_setup_ioctl(void) {
732 int i;
733
734 /* Set up character device for user mode clients */
735 i = register_chrdev(0, "pcmcia", &ds_fops);
736 if (i < 0)
737 printk(KERN_NOTICE "unable to find a free device # for "
738 "Driver Services (error=%d)\n", i);
739 else
740 major_dev = i;
741
742 #ifdef CONFIG_PROC_FS
743 proc_pccard = proc_mkdir("pccard", proc_bus);
744 if (proc_pccard)
745 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
746 #endif
747 }
748
749
750 void __exit pcmcia_cleanup_ioctl(void) {
751 #ifdef CONFIG_PROC_FS
752 if (proc_pccard) {
753 remove_proc_entry("drivers", proc_pccard);
754 remove_proc_entry("pccard", proc_bus);
755 }
756 #endif
757 if (major_dev != -1)
758 unregister_chrdev(major_dev, "pcmcia");
759 }
This page took 0.045693 seconds and 6 git commands to generate.