-/*
- * set general purpose IO pin state and direction
- *
- * user_gpio fields:
- * state each bit indicates a pin state
- * smask set bit indicates pin state to set
- * dir each bit indicates a pin direction (0=input, 1=output)
- * dmask set bit indicates pin direction to set
- */
-static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
-{
- unsigned long flags;
- struct gpio_desc gpio;
- __u32 data;
-
- if (!info->gpio_present)
- return -EINVAL;
- if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
- return -EFAULT;
- DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n",
- info->device_name, gpio.state, gpio.smask,
- gpio.dir, gpio.dmask));
-
- spin_lock_irqsave(&info->lock,flags);
- if (gpio.dmask) {
- data = rd_reg32(info, IODR);
- data |= gpio.dmask & gpio.dir;
- data &= ~(gpio.dmask & ~gpio.dir);
- wr_reg32(info, IODR, data);
- }
- if (gpio.smask) {
- data = rd_reg32(info, IOVR);
- data |= gpio.smask & gpio.state;
- data &= ~(gpio.smask & ~gpio.state);
- wr_reg32(info, IOVR, data);
- }
- spin_unlock_irqrestore(&info->lock,flags);
-
- return 0;
-}
-
-/*
- * get general purpose IO pin state and direction
- */
-static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
-{
- struct gpio_desc gpio;
- if (!info->gpio_present)
- return -EINVAL;
- gpio.state = rd_reg32(info, IOVR);
- gpio.smask = 0xffffffff;
- gpio.dir = rd_reg32(info, IODR);
- gpio.dmask = 0xffffffff;
- if (copy_to_user(user_gpio, &gpio, sizeof(gpio)))
- return -EFAULT;
- DBGINFO(("%s get_gpio state=%08x dir=%08x\n",
- info->device_name, gpio.state, gpio.dir));
- return 0;
-}
-
-/*
- * conditional wait facility
- */
-static void init_cond_wait(struct cond_wait *w, unsigned int data)
-{
- init_waitqueue_head(&w->q);
- init_waitqueue_entry(&w->wait, current);
- w->data = data;
-}
-
-static void add_cond_wait(struct cond_wait **head, struct cond_wait *w)
-{
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&w->q, &w->wait);
- w->next = *head;
- *head = w;
-}
-
-static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw)
-{
- struct cond_wait *w, *prev;
- remove_wait_queue(&cw->q, &cw->wait);
- set_current_state(TASK_RUNNING);
- for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) {
- if (w == cw) {
- if (prev != NULL)
- prev->next = w->next;
- else
- *head = w->next;
- break;
- }
- }
-}
-
-static void flush_cond_wait(struct cond_wait **head)
-{
- while (*head != NULL) {
- wake_up_interruptible(&(*head)->q);
- *head = (*head)->next;
- }
-}
-
-/*
- * wait for general purpose I/O pin(s) to enter specified state
- *
- * user_gpio fields:
- * state - bit indicates target pin state
- * smask - set bit indicates watched pin
- *
- * The wait ends when at least one watched pin enters the specified
- * state. When 0 (no error) is returned, user_gpio->state is set to the
- * state of all GPIO pins when the wait ends.
- *
- * Note: Each pin may be a dedicated input, dedicated output, or
- * configurable input/output. The number and configuration of pins
- * varies with the specific adapter model. Only input pins (dedicated
- * or configured) can be monitored with this function.
- */
-static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
-{
- unsigned long flags;
- int rc = 0;
- struct gpio_desc gpio;
- struct cond_wait wait;
- u32 state;
-
- if (!info->gpio_present)
- return -EINVAL;
- if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
- return -EFAULT;
- DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n",
- info->device_name, gpio.state, gpio.smask));
- /* ignore output pins identified by set IODR bit */
- if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0)
- return -EINVAL;
- init_cond_wait(&wait, gpio.smask);
-
- spin_lock_irqsave(&info->lock, flags);
- /* enable interrupts for watched pins */
- wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
- /* get current pin states */
- state = rd_reg32(info, IOVR);
-
- if (gpio.smask & ~(state ^ gpio.state)) {
- /* already in target state */
- gpio.state = state;
- } else {
- /* wait for target state */
- add_cond_wait(&info->gpio_wait_q, &wait);
- spin_unlock_irqrestore(&info->lock, flags);
- schedule();
- if (signal_pending(current))
- rc = -ERESTARTSYS;
- else
- gpio.state = wait.data;
- spin_lock_irqsave(&info->lock, flags);
- remove_cond_wait(&info->gpio_wait_q, &wait);
- }
-
- /* disable all GPIO interrupts if no waiting processes */
- if (info->gpio_wait_q == NULL)
- wr_reg32(info, IOER, 0);
- spin_unlock_irqrestore(&info->lock,flags);
-
- if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
- rc = -EFAULT;
- return rc;
-}
-