diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/cris/arch-v10/drivers/gpio.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index 080927ffe63b..a07b6d25b0c7 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/string.h> | 19 | #include <linux/string.h> |
21 | #include <linux/poll.h> | 20 | #include <linux/poll.h> |
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
@@ -46,7 +45,7 @@ static char gpio_name[] = "etrax gpio"; | |||
46 | static wait_queue_head_t *gpio_wq; | 45 | static wait_queue_head_t *gpio_wq; |
47 | #endif | 46 | #endif |
48 | 47 | ||
49 | static int gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 48 | static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
50 | static ssize_t gpio_write(struct file *file, const char __user *buf, | 49 | static ssize_t gpio_write(struct file *file, const char __user *buf, |
51 | size_t count, loff_t *off); | 50 | size_t count, loff_t *off); |
52 | static int gpio_open(struct inode *inode, struct file *filp); | 51 | static int gpio_open(struct inode *inode, struct file *filp); |
@@ -323,7 +322,6 @@ gpio_open(struct inode *inode, struct file *filp) | |||
323 | if (!priv) | 322 | if (!priv) |
324 | return -ENOMEM; | 323 | return -ENOMEM; |
325 | 324 | ||
326 | lock_kernel(); | ||
327 | priv->minor = p; | 325 | priv->minor = p; |
328 | 326 | ||
329 | /* initialize the io/alarm struct */ | 327 | /* initialize the io/alarm struct */ |
@@ -358,7 +356,6 @@ gpio_open(struct inode *inode, struct file *filp) | |||
358 | alarmlist = priv; | 356 | alarmlist = priv; |
359 | spin_unlock_irqrestore(&gpio_lock, flags); | 357 | spin_unlock_irqrestore(&gpio_lock, flags); |
360 | 358 | ||
361 | unlock_kernel(); | ||
362 | return 0; | 359 | return 0; |
363 | } | 360 | } |
364 | 361 | ||
@@ -503,8 +500,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) | |||
503 | static int | 500 | static int |
504 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg); | 501 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg); |
505 | 502 | ||
506 | static int | 503 | static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
507 | gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | ||
508 | { | 504 | { |
509 | unsigned long flags; | 505 | unsigned long flags; |
510 | unsigned long val; | 506 | unsigned long val; |
@@ -514,54 +510,65 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
514 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) | 510 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) |
515 | return -EINVAL; | 511 | return -EINVAL; |
516 | 512 | ||
517 | spin_lock_irqsave(&gpio_lock, flags); | ||
518 | |||
519 | switch (_IOC_NR(cmd)) { | 513 | switch (_IOC_NR(cmd)) { |
520 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | 514 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ |
521 | // read the port | 515 | // read the port |
516 | spin_lock_irqsave(&gpio_lock, flags); | ||
522 | if (USE_PORTS(priv)) { | 517 | if (USE_PORTS(priv)) { |
523 | ret = *priv->port; | 518 | ret = *priv->port; |
524 | } else if (priv->minor == GPIO_MINOR_G) { | 519 | } else if (priv->minor == GPIO_MINOR_G) { |
525 | ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; | 520 | ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; |
526 | } | 521 | } |
522 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
523 | |||
527 | break; | 524 | break; |
528 | case IO_SETBITS: | 525 | case IO_SETBITS: |
529 | // set changeable bits with a 1 in arg | 526 | // set changeable bits with a 1 in arg |
527 | spin_lock_irqsave(&gpio_lock, flags); | ||
528 | |||
530 | if (USE_PORTS(priv)) { | 529 | if (USE_PORTS(priv)) { |
531 | *priv->port = *priv->shadow |= | 530 | *priv->port = *priv->shadow |= |
532 | ((unsigned char)arg & priv->changeable_bits); | 531 | ((unsigned char)arg & priv->changeable_bits); |
533 | } else if (priv->minor == GPIO_MINOR_G) { | 532 | } else if (priv->minor == GPIO_MINOR_G) { |
534 | *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); | 533 | *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); |
535 | } | 534 | } |
535 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
536 | |||
536 | break; | 537 | break; |
537 | case IO_CLRBITS: | 538 | case IO_CLRBITS: |
538 | // clear changeable bits with a 1 in arg | 539 | // clear changeable bits with a 1 in arg |
540 | spin_lock_irqsave(&gpio_lock, flags); | ||
539 | if (USE_PORTS(priv)) { | 541 | if (USE_PORTS(priv)) { |
540 | *priv->port = *priv->shadow &= | 542 | *priv->port = *priv->shadow &= |
541 | ~((unsigned char)arg & priv->changeable_bits); | 543 | ~((unsigned char)arg & priv->changeable_bits); |
542 | } else if (priv->minor == GPIO_MINOR_G) { | 544 | } else if (priv->minor == GPIO_MINOR_G) { |
543 | *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); | 545 | *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); |
544 | } | 546 | } |
547 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
545 | break; | 548 | break; |
546 | case IO_HIGHALARM: | 549 | case IO_HIGHALARM: |
547 | // set alarm when bits with 1 in arg go high | 550 | // set alarm when bits with 1 in arg go high |
551 | spin_lock_irqsave(&gpio_lock, flags); | ||
548 | priv->highalarm |= arg; | 552 | priv->highalarm |= arg; |
549 | gpio_some_alarms = 1; | 553 | gpio_some_alarms = 1; |
554 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
550 | break; | 555 | break; |
551 | case IO_LOWALARM: | 556 | case IO_LOWALARM: |
552 | // set alarm when bits with 1 in arg go low | 557 | // set alarm when bits with 1 in arg go low |
558 | spin_lock_irqsave(&gpio_lock, flags); | ||
553 | priv->lowalarm |= arg; | 559 | priv->lowalarm |= arg; |
554 | gpio_some_alarms = 1; | 560 | gpio_some_alarms = 1; |
561 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
555 | break; | 562 | break; |
556 | case IO_CLRALARM: | 563 | case IO_CLRALARM: |
557 | // clear alarm for bits with 1 in arg | 564 | /* clear alarm for bits with 1 in arg */ |
565 | spin_lock_irqsave(&gpio_lock, flags); | ||
558 | priv->highalarm &= ~arg; | 566 | priv->highalarm &= ~arg; |
559 | priv->lowalarm &= ~arg; | 567 | priv->lowalarm &= ~arg; |
560 | { | 568 | { |
561 | /* Must update gpio_some_alarms */ | 569 | /* Must update gpio_some_alarms */ |
562 | struct gpio_private *p = alarmlist; | 570 | struct gpio_private *p = alarmlist; |
563 | int some_alarms; | 571 | int some_alarms; |
564 | spin_lock_irq(&gpio_lock); | ||
565 | p = alarmlist; | 572 | p = alarmlist; |
566 | some_alarms = 0; | 573 | some_alarms = 0; |
567 | while (p) { | 574 | while (p) { |
@@ -572,11 +579,12 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
572 | p = p->next; | 579 | p = p->next; |
573 | } | 580 | } |
574 | gpio_some_alarms = some_alarms; | 581 | gpio_some_alarms = some_alarms; |
575 | spin_unlock_irq(&gpio_lock); | ||
576 | } | 582 | } |
583 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
577 | break; | 584 | break; |
578 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | 585 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ |
579 | /* Read direction 0=input 1=output */ | 586 | /* Read direction 0=input 1=output */ |
587 | spin_lock_irqsave(&gpio_lock, flags); | ||
580 | if (USE_PORTS(priv)) { | 588 | if (USE_PORTS(priv)) { |
581 | ret = *priv->dir_shadow; | 589 | ret = *priv->dir_shadow; |
582 | } else if (priv->minor == GPIO_MINOR_G) { | 590 | } else if (priv->minor == GPIO_MINOR_G) { |
@@ -585,30 +593,40 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
585 | */ | 593 | */ |
586 | ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; | 594 | ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; |
587 | } | 595 | } |
596 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
588 | break; | 597 | break; |
589 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ | 598 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ |
590 | /* Set direction 0=unchanged 1=input, | 599 | /* Set direction 0=unchanged 1=input, |
591 | * return mask with 1=input | 600 | * return mask with 1=input |
592 | */ | 601 | */ |
602 | spin_lock_irqsave(&gpio_lock, flags); | ||
593 | ret = setget_input(priv, arg) & 0x7FFFFFFF; | 603 | ret = setget_input(priv, arg) & 0x7FFFFFFF; |
604 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
594 | break; | 605 | break; |
595 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ | 606 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ |
596 | /* Set direction 0=unchanged 1=output, | 607 | /* Set direction 0=unchanged 1=output, |
597 | * return mask with 1=output | 608 | * return mask with 1=output |
598 | */ | 609 | */ |
610 | spin_lock_irqsave(&gpio_lock, flags); | ||
599 | ret = setget_output(priv, arg) & 0x7FFFFFFF; | 611 | ret = setget_output(priv, arg) & 0x7FFFFFFF; |
612 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
600 | break; | 613 | break; |
601 | case IO_SHUTDOWN: | 614 | case IO_SHUTDOWN: |
615 | spin_lock_irqsave(&gpio_lock, flags); | ||
602 | SOFT_SHUTDOWN(); | 616 | SOFT_SHUTDOWN(); |
617 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
603 | break; | 618 | break; |
604 | case IO_GET_PWR_BT: | 619 | case IO_GET_PWR_BT: |
620 | spin_lock_irqsave(&gpio_lock, flags); | ||
605 | #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) | 621 | #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) |
606 | ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); | 622 | ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); |
607 | #else | 623 | #else |
608 | ret = 0; | 624 | ret = 0; |
609 | #endif | 625 | #endif |
626 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
610 | break; | 627 | break; |
611 | case IO_CFG_WRITE_MODE: | 628 | case IO_CFG_WRITE_MODE: |
629 | spin_lock_irqsave(&gpio_lock, flags); | ||
612 | priv->clk_mask = arg & 0xFF; | 630 | priv->clk_mask = arg & 0xFF; |
613 | priv->data_mask = (arg >> 8) & 0xFF; | 631 | priv->data_mask = (arg >> 8) & 0xFF; |
614 | priv->write_msb = (arg >> 16) & 0x01; | 632 | priv->write_msb = (arg >> 16) & 0x01; |
@@ -624,28 +642,33 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
624 | priv->data_mask = 0; | 642 | priv->data_mask = 0; |
625 | ret = -EPERM; | 643 | ret = -EPERM; |
626 | } | 644 | } |
645 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
627 | break; | 646 | break; |
628 | case IO_READ_INBITS: | 647 | case IO_READ_INBITS: |
629 | /* *arg is result of reading the input pins */ | 648 | /* *arg is result of reading the input pins */ |
649 | spin_lock_irqsave(&gpio_lock, flags); | ||
630 | if (USE_PORTS(priv)) { | 650 | if (USE_PORTS(priv)) { |
631 | val = *priv->port; | 651 | val = *priv->port; |
632 | } else if (priv->minor == GPIO_MINOR_G) { | 652 | } else if (priv->minor == GPIO_MINOR_G) { |
633 | val = *R_PORT_G_DATA; | 653 | val = *R_PORT_G_DATA; |
634 | } | 654 | } |
655 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
635 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | 656 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
636 | ret = -EFAULT; | 657 | ret = -EFAULT; |
637 | break; | 658 | break; |
638 | case IO_READ_OUTBITS: | 659 | case IO_READ_OUTBITS: |
639 | /* *arg is result of reading the output shadow */ | 660 | /* *arg is result of reading the output shadow */ |
661 | spin_lock_irqsave(&gpio_lock, flags); | ||
640 | if (USE_PORTS(priv)) { | 662 | if (USE_PORTS(priv)) { |
641 | val = *priv->shadow; | 663 | val = *priv->shadow; |
642 | } else if (priv->minor == GPIO_MINOR_G) { | 664 | } else if (priv->minor == GPIO_MINOR_G) { |
643 | val = port_g_data_shadow; | 665 | val = port_g_data_shadow; |
644 | } | 666 | } |
667 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
645 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | 668 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
646 | ret = -EFAULT; | 669 | ret = -EFAULT; |
647 | break; | 670 | break; |
648 | case IO_SETGET_INPUT: | 671 | case IO_SETGET_INPUT: |
649 | /* bits set in *arg is set to input, | 672 | /* bits set in *arg is set to input, |
650 | * *arg updated with current input pins. | 673 | * *arg updated with current input pins. |
651 | */ | 674 | */ |
@@ -654,7 +677,9 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
654 | ret = -EFAULT; | 677 | ret = -EFAULT; |
655 | break; | 678 | break; |
656 | } | 679 | } |
680 | spin_lock_irqsave(&gpio_lock, flags); | ||
657 | val = setget_input(priv, val); | 681 | val = setget_input(priv, val); |
682 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
658 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | 683 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
659 | ret = -EFAULT; | 684 | ret = -EFAULT; |
660 | break; | 685 | break; |
@@ -666,34 +691,25 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) | |||
666 | ret = -EFAULT; | 691 | ret = -EFAULT; |
667 | break; | 692 | break; |
668 | } | 693 | } |
694 | spin_lock_irqsave(&gpio_lock, flags); | ||
669 | val = setget_output(priv, val); | 695 | val = setget_output(priv, val); |
696 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
670 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | 697 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
671 | ret = -EFAULT; | 698 | ret = -EFAULT; |
672 | break; | 699 | break; |
673 | default: | 700 | default: |
701 | spin_lock_irqsave(&gpio_lock, flags); | ||
674 | if (priv->minor == GPIO_MINOR_LEDS) | 702 | if (priv->minor == GPIO_MINOR_LEDS) |
675 | ret = gpio_leds_ioctl(cmd, arg); | 703 | ret = gpio_leds_ioctl(cmd, arg); |
676 | else | 704 | else |
677 | ret = -EINVAL; | 705 | ret = -EINVAL; |
706 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
678 | } /* switch */ | 707 | } /* switch */ |
679 | 708 | ||
680 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
681 | return ret; | 709 | return ret; |
682 | } | 710 | } |
683 | 711 | ||
684 | static int | 712 | static int |
685 | gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
686 | { | ||
687 | long ret; | ||
688 | |||
689 | lock_kernel(); | ||
690 | ret = gpio_ioctl_unlocked(file, cmd, arg); | ||
691 | unlock_kernel(); | ||
692 | |||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | static int | ||
697 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | 713 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) |
698 | { | 714 | { |
699 | unsigned char green; | 715 | unsigned char green; |