diff options
author | Paul Fulghum <paulkf@microgate.com> | 2006-03-28 04:56:15 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-28 12:16:02 -0500 |
commit | 0080b7aae88c75e2a6b38dfcb228b0f239e18e3c (patch) | |
tree | 445aadcb5f4e6271d9dfc6a35395a0a3a57716c6 | |
parent | 86a34147d1f1c94e94500e63e83f9fa42548a088 (diff) |
[PATCH] synclink_gt add gpio feature
Add driver support for general purpose I/O feature of the Synclink GT
adapters.
Signed-off-by: Paul Fulghum <paulkf@micrgate.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/char/synclink_gt.c | 246 | ||||
-rw-r--r-- | include/linux/synclink.h | 11 |
2 files changed, 252 insertions, 5 deletions
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 738ec2f4e563..8818042bad7c 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: synclink_gt.c,v 4.22 2006/01/09 20:16:06 paulkf Exp $ | 2 | * $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $ |
3 | * | 3 | * |
4 | * Device driver for Microgate SyncLink GT serial adapters. | 4 | * Device driver for Microgate SyncLink GT serial adapters. |
5 | * | 5 | * |
@@ -92,7 +92,7 @@ | |||
92 | * module identification | 92 | * module identification |
93 | */ | 93 | */ |
94 | static char *driver_name = "SyncLink GT"; | 94 | static char *driver_name = "SyncLink GT"; |
95 | static char *driver_version = "$Revision: 4.22 $"; | 95 | static char *driver_version = "$Revision: 4.25 $"; |
96 | static char *tty_driver_name = "synclink_gt"; | 96 | static char *tty_driver_name = "synclink_gt"; |
97 | static char *tty_dev_prefix = "ttySLG"; | 97 | static char *tty_dev_prefix = "ttySLG"; |
98 | MODULE_LICENSE("GPL"); | 98 | MODULE_LICENSE("GPL"); |
@@ -188,6 +188,20 @@ static void hdlcdev_exit(struct slgt_info *info); | |||
188 | #define SLGT_REG_SIZE 256 | 188 | #define SLGT_REG_SIZE 256 |
189 | 189 | ||
190 | /* | 190 | /* |
191 | * conditional wait facility | ||
192 | */ | ||
193 | struct cond_wait { | ||
194 | struct cond_wait *next; | ||
195 | wait_queue_head_t q; | ||
196 | wait_queue_t wait; | ||
197 | unsigned int data; | ||
198 | }; | ||
199 | static void init_cond_wait(struct cond_wait *w, unsigned int data); | ||
200 | static void add_cond_wait(struct cond_wait **head, struct cond_wait *w); | ||
201 | static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w); | ||
202 | static void flush_cond_wait(struct cond_wait **head); | ||
203 | |||
204 | /* | ||
191 | * DMA buffer descriptor and access macros | 205 | * DMA buffer descriptor and access macros |
192 | */ | 206 | */ |
193 | struct slgt_desc | 207 | struct slgt_desc |
@@ -269,6 +283,9 @@ struct slgt_info { | |||
269 | struct timer_list tx_timer; | 283 | struct timer_list tx_timer; |
270 | struct timer_list rx_timer; | 284 | struct timer_list rx_timer; |
271 | 285 | ||
286 | unsigned int gpio_present; | ||
287 | struct cond_wait *gpio_wait_q; | ||
288 | |||
272 | spinlock_t lock; /* spinlock for synchronizing with ISR */ | 289 | spinlock_t lock; /* spinlock for synchronizing with ISR */ |
273 | 290 | ||
274 | struct work_struct task; | 291 | struct work_struct task; |
@@ -379,6 +396,11 @@ static MGSL_PARAMS default_params = { | |||
379 | #define MASK_OVERRUN BIT4 | 396 | #define MASK_OVERRUN BIT4 |
380 | 397 | ||
381 | #define GSR 0x00 /* global status */ | 398 | #define GSR 0x00 /* global status */ |
399 | #define JCR 0x04 /* JTAG control */ | ||
400 | #define IODR 0x08 /* GPIO direction */ | ||
401 | #define IOER 0x0c /* GPIO interrupt enable */ | ||
402 | #define IOVR 0x10 /* GPIO value */ | ||
403 | #define IOSR 0x14 /* GPIO interrupt status */ | ||
382 | #define TDR 0x80 /* tx data */ | 404 | #define TDR 0x80 /* tx data */ |
383 | #define RDR 0x80 /* rx data */ | 405 | #define RDR 0x80 /* rx data */ |
384 | #define TCR 0x82 /* tx control */ | 406 | #define TCR 0x82 /* tx control */ |
@@ -503,6 +525,9 @@ static int tiocmset(struct tty_struct *tty, struct file *file, | |||
503 | static void set_break(struct tty_struct *tty, int break_state); | 525 | static void set_break(struct tty_struct *tty, int break_state); |
504 | static int get_interface(struct slgt_info *info, int __user *if_mode); | 526 | static int get_interface(struct slgt_info *info, int __user *if_mode); |
505 | static int set_interface(struct slgt_info *info, int if_mode); | 527 | static int set_interface(struct slgt_info *info, int if_mode); |
528 | static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
529 | static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
530 | static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
506 | 531 | ||
507 | /* | 532 | /* |
508 | * driver functions | 533 | * driver functions |
@@ -1112,6 +1137,12 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1112 | return get_interface(info, argp); | 1137 | return get_interface(info, argp); |
1113 | case MGSL_IOCSIF: | 1138 | case MGSL_IOCSIF: |
1114 | return set_interface(info,(int)arg); | 1139 | return set_interface(info,(int)arg); |
1140 | case MGSL_IOCSGPIO: | ||
1141 | return set_gpio(info, argp); | ||
1142 | case MGSL_IOCGGPIO: | ||
1143 | return get_gpio(info, argp); | ||
1144 | case MGSL_IOCWAITGPIO: | ||
1145 | return wait_gpio(info, argp); | ||
1115 | case TIOCGICOUNT: | 1146 | case TIOCGICOUNT: |
1116 | spin_lock_irqsave(&info->lock,flags); | 1147 | spin_lock_irqsave(&info->lock,flags); |
1117 | cnow = info->icount; | 1148 | cnow = info->icount; |
@@ -2158,6 +2189,24 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) | |||
2158 | } | 2189 | } |
2159 | } | 2190 | } |
2160 | 2191 | ||
2192 | static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state) | ||
2193 | { | ||
2194 | struct cond_wait *w, *prev; | ||
2195 | |||
2196 | /* wake processes waiting for specific transitions */ | ||
2197 | for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) { | ||
2198 | if (w->data & changed) { | ||
2199 | w->data = state; | ||
2200 | wake_up_interruptible(&w->q); | ||
2201 | if (prev != NULL) | ||
2202 | prev->next = w->next; | ||
2203 | else | ||
2204 | info->gpio_wait_q = w->next; | ||
2205 | } else | ||
2206 | prev = w; | ||
2207 | } | ||
2208 | } | ||
2209 | |||
2161 | /* interrupt service routine | 2210 | /* interrupt service routine |
2162 | * | 2211 | * |
2163 | * irq interrupt number | 2212 | * irq interrupt number |
@@ -2193,6 +2242,22 @@ static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
2193 | } | 2242 | } |
2194 | } | 2243 | } |
2195 | 2244 | ||
2245 | if (info->gpio_present) { | ||
2246 | unsigned int state; | ||
2247 | unsigned int changed; | ||
2248 | while ((changed = rd_reg32(info, IOSR)) != 0) { | ||
2249 | DBGISR(("%s iosr=%08x\n", info->device_name, changed)); | ||
2250 | /* read latched state of GPIO signals */ | ||
2251 | state = rd_reg32(info, IOVR); | ||
2252 | /* clear pending GPIO interrupt bits */ | ||
2253 | wr_reg32(info, IOSR, changed); | ||
2254 | for (i=0 ; i < info->port_count ; i++) { | ||
2255 | if (info->port_array[i] != NULL) | ||
2256 | isr_gpio(info->port_array[i], changed, state); | ||
2257 | } | ||
2258 | } | ||
2259 | } | ||
2260 | |||
2196 | for(i=0; i < info->port_count ; i++) { | 2261 | for(i=0; i < info->port_count ; i++) { |
2197 | struct slgt_info *port = info->port_array[i]; | 2262 | struct slgt_info *port = info->port_array[i]; |
2198 | 2263 | ||
@@ -2276,6 +2341,8 @@ static void shutdown(struct slgt_info *info) | |||
2276 | set_signals(info); | 2341 | set_signals(info); |
2277 | } | 2342 | } |
2278 | 2343 | ||
2344 | flush_cond_wait(&info->gpio_wait_q); | ||
2345 | |||
2279 | spin_unlock_irqrestore(&info->lock,flags); | 2346 | spin_unlock_irqrestore(&info->lock,flags); |
2280 | 2347 | ||
2281 | if (info->tty) | 2348 | if (info->tty) |
@@ -2650,6 +2717,175 @@ static int set_interface(struct slgt_info *info, int if_mode) | |||
2650 | return 0; | 2717 | return 0; |
2651 | } | 2718 | } |
2652 | 2719 | ||
2720 | /* | ||
2721 | * set general purpose IO pin state and direction | ||
2722 | * | ||
2723 | * user_gpio fields: | ||
2724 | * state each bit indicates a pin state | ||
2725 | * smask set bit indicates pin state to set | ||
2726 | * dir each bit indicates a pin direction (0=input, 1=output) | ||
2727 | * dmask set bit indicates pin direction to set | ||
2728 | */ | ||
2729 | static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
2730 | { | ||
2731 | unsigned long flags; | ||
2732 | struct gpio_desc gpio; | ||
2733 | __u32 data; | ||
2734 | |||
2735 | if (!info->gpio_present) | ||
2736 | return -EINVAL; | ||
2737 | if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) | ||
2738 | return -EFAULT; | ||
2739 | DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n", | ||
2740 | info->device_name, gpio.state, gpio.smask, | ||
2741 | gpio.dir, gpio.dmask)); | ||
2742 | |||
2743 | spin_lock_irqsave(&info->lock,flags); | ||
2744 | if (gpio.dmask) { | ||
2745 | data = rd_reg32(info, IODR); | ||
2746 | data |= gpio.dmask & gpio.dir; | ||
2747 | data &= ~(gpio.dmask & ~gpio.dir); | ||
2748 | wr_reg32(info, IODR, data); | ||
2749 | } | ||
2750 | if (gpio.smask) { | ||
2751 | data = rd_reg32(info, IOVR); | ||
2752 | data |= gpio.smask & gpio.state; | ||
2753 | data &= ~(gpio.smask & ~gpio.state); | ||
2754 | wr_reg32(info, IOVR, data); | ||
2755 | } | ||
2756 | spin_unlock_irqrestore(&info->lock,flags); | ||
2757 | |||
2758 | return 0; | ||
2759 | } | ||
2760 | |||
2761 | /* | ||
2762 | * get general purpose IO pin state and direction | ||
2763 | */ | ||
2764 | static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
2765 | { | ||
2766 | struct gpio_desc gpio; | ||
2767 | if (!info->gpio_present) | ||
2768 | return -EINVAL; | ||
2769 | gpio.state = rd_reg32(info, IOVR); | ||
2770 | gpio.smask = 0xffffffff; | ||
2771 | gpio.dir = rd_reg32(info, IODR); | ||
2772 | gpio.dmask = 0xffffffff; | ||
2773 | if (copy_to_user(user_gpio, &gpio, sizeof(gpio))) | ||
2774 | return -EFAULT; | ||
2775 | DBGINFO(("%s get_gpio state=%08x dir=%08x\n", | ||
2776 | info->device_name, gpio.state, gpio.dir)); | ||
2777 | return 0; | ||
2778 | } | ||
2779 | |||
2780 | /* | ||
2781 | * conditional wait facility | ||
2782 | */ | ||
2783 | static void init_cond_wait(struct cond_wait *w, unsigned int data) | ||
2784 | { | ||
2785 | init_waitqueue_head(&w->q); | ||
2786 | init_waitqueue_entry(&w->wait, current); | ||
2787 | w->data = data; | ||
2788 | } | ||
2789 | |||
2790 | static void add_cond_wait(struct cond_wait **head, struct cond_wait *w) | ||
2791 | { | ||
2792 | set_current_state(TASK_INTERRUPTIBLE); | ||
2793 | add_wait_queue(&w->q, &w->wait); | ||
2794 | w->next = *head; | ||
2795 | *head = w; | ||
2796 | } | ||
2797 | |||
2798 | static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw) | ||
2799 | { | ||
2800 | struct cond_wait *w, *prev; | ||
2801 | remove_wait_queue(&cw->q, &cw->wait); | ||
2802 | set_current_state(TASK_RUNNING); | ||
2803 | for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) { | ||
2804 | if (w == cw) { | ||
2805 | if (prev != NULL) | ||
2806 | prev->next = w->next; | ||
2807 | else | ||
2808 | *head = w->next; | ||
2809 | break; | ||
2810 | } | ||
2811 | } | ||
2812 | } | ||
2813 | |||
2814 | static void flush_cond_wait(struct cond_wait **head) | ||
2815 | { | ||
2816 | while (*head != NULL) { | ||
2817 | wake_up_interruptible(&(*head)->q); | ||
2818 | *head = (*head)->next; | ||
2819 | } | ||
2820 | } | ||
2821 | |||
2822 | /* | ||
2823 | * wait for general purpose I/O pin(s) to enter specified state | ||
2824 | * | ||
2825 | * user_gpio fields: | ||
2826 | * state - bit indicates target pin state | ||
2827 | * smask - set bit indicates watched pin | ||
2828 | * | ||
2829 | * The wait ends when at least one watched pin enters the specified | ||
2830 | * state. When 0 (no error) is returned, user_gpio->state is set to the | ||
2831 | * state of all GPIO pins when the wait ends. | ||
2832 | * | ||
2833 | * Note: Each pin may be a dedicated input, dedicated output, or | ||
2834 | * configurable input/output. The number and configuration of pins | ||
2835 | * varies with the specific adapter model. Only input pins (dedicated | ||
2836 | * or configured) can be monitored with this function. | ||
2837 | */ | ||
2838 | static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
2839 | { | ||
2840 | unsigned long flags; | ||
2841 | int rc = 0; | ||
2842 | struct gpio_desc gpio; | ||
2843 | struct cond_wait wait; | ||
2844 | u32 state; | ||
2845 | |||
2846 | if (!info->gpio_present) | ||
2847 | return -EINVAL; | ||
2848 | if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) | ||
2849 | return -EFAULT; | ||
2850 | DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n", | ||
2851 | info->device_name, gpio.state, gpio.smask)); | ||
2852 | /* ignore output pins identified by set IODR bit */ | ||
2853 | if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0) | ||
2854 | return -EINVAL; | ||
2855 | init_cond_wait(&wait, gpio.smask); | ||
2856 | |||
2857 | spin_lock_irqsave(&info->lock, flags); | ||
2858 | /* enable interrupts for watched pins */ | ||
2859 | wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask); | ||
2860 | /* get current pin states */ | ||
2861 | state = rd_reg32(info, IOVR); | ||
2862 | |||
2863 | if (gpio.smask & ~(state ^ gpio.state)) { | ||
2864 | /* already in target state */ | ||
2865 | gpio.state = state; | ||
2866 | } else { | ||
2867 | /* wait for target state */ | ||
2868 | add_cond_wait(&info->gpio_wait_q, &wait); | ||
2869 | spin_unlock_irqrestore(&info->lock, flags); | ||
2870 | schedule(); | ||
2871 | if (signal_pending(current)) | ||
2872 | rc = -ERESTARTSYS; | ||
2873 | else | ||
2874 | gpio.state = wait.data; | ||
2875 | spin_lock_irqsave(&info->lock, flags); | ||
2876 | remove_cond_wait(&info->gpio_wait_q, &wait); | ||
2877 | } | ||
2878 | |||
2879 | /* disable all GPIO interrupts if no waiting processes */ | ||
2880 | if (info->gpio_wait_q == NULL) | ||
2881 | wr_reg32(info, IOER, 0); | ||
2882 | spin_unlock_irqrestore(&info->lock,flags); | ||
2883 | |||
2884 | if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio))) | ||
2885 | rc = -EFAULT; | ||
2886 | return rc; | ||
2887 | } | ||
2888 | |||
2653 | static int modem_input_wait(struct slgt_info *info,int arg) | 2889 | static int modem_input_wait(struct slgt_info *info,int arg) |
2654 | { | 2890 | { |
2655 | unsigned long flags; | 2891 | unsigned long flags; |
@@ -3166,8 +3402,10 @@ static void device_init(int adapter_num, struct pci_dev *pdev) | |||
3166 | } else { | 3402 | } else { |
3167 | port_array[0]->irq_requested = 1; | 3403 | port_array[0]->irq_requested = 1; |
3168 | adapter_test(port_array[0]); | 3404 | adapter_test(port_array[0]); |
3169 | for (i=1 ; i < port_count ; i++) | 3405 | for (i=1 ; i < port_count ; i++) { |
3170 | port_array[i]->init_error = port_array[0]->init_error; | 3406 | port_array[i]->init_error = port_array[0]->init_error; |
3407 | port_array[i]->gpio_present = port_array[0]->gpio_present; | ||
3408 | } | ||
3171 | } | 3409 | } |
3172 | } | 3410 | } |
3173 | } | 3411 | } |
@@ -4301,7 +4539,7 @@ static int register_test(struct slgt_info *info) | |||
4301 | break; | 4539 | break; |
4302 | } | 4540 | } |
4303 | } | 4541 | } |
4304 | 4542 | info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0; | |
4305 | info->init_error = rc ? 0 : DiagStatus_AddressFailure; | 4543 | info->init_error = rc ? 0 : DiagStatus_AddressFailure; |
4306 | return rc; | 4544 | return rc; |
4307 | } | 4545 | } |
diff --git a/include/linux/synclink.h b/include/linux/synclink.h index 1b7cd8d1a71b..2993302f7923 100644 --- a/include/linux/synclink.h +++ b/include/linux/synclink.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SyncLink Multiprotocol Serial Adapter Driver | 2 | * SyncLink Multiprotocol Serial Adapter Driver |
3 | * | 3 | * |
4 | * $Id: synclink.h,v 3.10 2005/11/08 19:50:54 paulkf Exp $ | 4 | * $Id: synclink.h,v 3.11 2006/02/06 21:20:29 paulkf Exp $ |
5 | * | 5 | * |
6 | * Copyright (C) 1998-2000 by Microgate Corporation | 6 | * Copyright (C) 1998-2000 by Microgate Corporation |
7 | * | 7 | * |
@@ -221,6 +221,12 @@ struct mgsl_icount { | |||
221 | __u32 rxidle; | 221 | __u32 rxidle; |
222 | }; | 222 | }; |
223 | 223 | ||
224 | struct gpio_desc { | ||
225 | __u32 state; | ||
226 | __u32 smask; | ||
227 | __u32 dir; | ||
228 | __u32 dmask; | ||
229 | }; | ||
224 | 230 | ||
225 | #define DEBUG_LEVEL_DATA 1 | 231 | #define DEBUG_LEVEL_DATA 1 |
226 | #define DEBUG_LEVEL_ERROR 2 | 232 | #define DEBUG_LEVEL_ERROR 2 |
@@ -276,5 +282,8 @@ struct mgsl_icount { | |||
276 | #define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9) | 282 | #define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9) |
277 | #define MGSL_IOCSIF _IO(MGSL_MAGIC_IOC,10) | 283 | #define MGSL_IOCSIF _IO(MGSL_MAGIC_IOC,10) |
278 | #define MGSL_IOCGIF _IO(MGSL_MAGIC_IOC,11) | 284 | #define MGSL_IOCGIF _IO(MGSL_MAGIC_IOC,11) |
285 | #define MGSL_IOCSGPIO _IOW(MGSL_MAGIC_IOC,16,struct gpio_desc) | ||
286 | #define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc) | ||
287 | #define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc) | ||
279 | 288 | ||
280 | #endif /* _SYNCLINK_H_ */ | 289 | #endif /* _SYNCLINK_H_ */ |