diff options
author | Alan Cox <alan@redhat.com> | 2009-01-02 08:45:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 13:19:38 -0500 |
commit | 31f35939d1d9bcfb3099b32c67b896d2792603f9 (patch) | |
tree | 39b6ceaf0e7477e0357ff8235814f579adad3f28 /drivers/char/synclink_gt.c | |
parent | c9b3976e3fec266be25c5001a70aa0a890b6c476 (diff) |
tty_port: Add a port level carrier detect operation
This is the first step to generalising the various pieces of waiting logic
duplicated in all sorts of serial drivers.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/synclink_gt.c')
-rw-r--r-- | drivers/char/synclink_gt.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 08911ed66494..39ccaba8ca37 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -3132,6 +3132,17 @@ static int tiocmset(struct tty_struct *tty, struct file *file, | |||
3132 | return 0; | 3132 | return 0; |
3133 | } | 3133 | } |
3134 | 3134 | ||
3135 | static int carrier_raised(struct tty_port *port) | ||
3136 | { | ||
3137 | unsigned long flags; | ||
3138 | struct slgt_info *info = container_of(port, struct slgt_info, port); | ||
3139 | |||
3140 | spin_lock_irqsave(&info->lock,flags); | ||
3141 | get_signals(info); | ||
3142 | spin_unlock_irqrestore(&info->lock,flags); | ||
3143 | return (info->signals & SerialSignal_DCD) ? 1 : 0; | ||
3144 | } | ||
3145 | |||
3135 | /* | 3146 | /* |
3136 | * block current process until the device is ready to open | 3147 | * block current process until the device is ready to open |
3137 | */ | 3148 | */ |
@@ -3143,12 +3154,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
3143 | bool do_clocal = false; | 3154 | bool do_clocal = false; |
3144 | bool extra_count = false; | 3155 | bool extra_count = false; |
3145 | unsigned long flags; | 3156 | unsigned long flags; |
3157 | int cd; | ||
3158 | struct tty_port *port = &info->port; | ||
3146 | 3159 | ||
3147 | DBGINFO(("%s block_til_ready\n", tty->driver->name)); | 3160 | DBGINFO(("%s block_til_ready\n", tty->driver->name)); |
3148 | 3161 | ||
3149 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ | 3162 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ |
3150 | /* nonblock mode is set or port is not enabled */ | 3163 | /* nonblock mode is set or port is not enabled */ |
3151 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 3164 | port->flags |= ASYNC_NORMAL_ACTIVE; |
3152 | return 0; | 3165 | return 0; |
3153 | } | 3166 | } |
3154 | 3167 | ||
@@ -3157,21 +3170,21 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
3157 | 3170 | ||
3158 | /* Wait for carrier detect and the line to become | 3171 | /* Wait for carrier detect and the line to become |
3159 | * free (i.e., not in use by the callout). While we are in | 3172 | * free (i.e., not in use by the callout). While we are in |
3160 | * this loop, info->port.count is dropped by one, so that | 3173 | * this loop, port->count is dropped by one, so that |
3161 | * close() knows when to free things. We restore it upon | 3174 | * close() knows when to free things. We restore it upon |
3162 | * exit, either normal or abnormal. | 3175 | * exit, either normal or abnormal. |
3163 | */ | 3176 | */ |
3164 | 3177 | ||
3165 | retval = 0; | 3178 | retval = 0; |
3166 | add_wait_queue(&info->port.open_wait, &wait); | 3179 | add_wait_queue(&port->open_wait, &wait); |
3167 | 3180 | ||
3168 | spin_lock_irqsave(&info->lock, flags); | 3181 | spin_lock_irqsave(&info->lock, flags); |
3169 | if (!tty_hung_up_p(filp)) { | 3182 | if (!tty_hung_up_p(filp)) { |
3170 | extra_count = true; | 3183 | extra_count = true; |
3171 | info->port.count--; | 3184 | port->count--; |
3172 | } | 3185 | } |
3173 | spin_unlock_irqrestore(&info->lock, flags); | 3186 | spin_unlock_irqrestore(&info->lock, flags); |
3174 | info->port.blocked_open++; | 3187 | port->blocked_open++; |
3175 | 3188 | ||
3176 | while (1) { | 3189 | while (1) { |
3177 | if ((tty->termios->c_cflag & CBAUD)) { | 3190 | if ((tty->termios->c_cflag & CBAUD)) { |
@@ -3183,20 +3196,16 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
3183 | 3196 | ||
3184 | set_current_state(TASK_INTERRUPTIBLE); | 3197 | set_current_state(TASK_INTERRUPTIBLE); |
3185 | 3198 | ||
3186 | if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ | 3199 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ |
3187 | retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? | 3200 | retval = (port->flags & ASYNC_HUP_NOTIFY) ? |
3188 | -EAGAIN : -ERESTARTSYS; | 3201 | -EAGAIN : -ERESTARTSYS; |
3189 | break; | 3202 | break; |
3190 | } | 3203 | } |
3191 | 3204 | ||
3192 | spin_lock_irqsave(&info->lock,flags); | 3205 | cd = tty_port_carrier_raised(port); |
3193 | get_signals(info); | ||
3194 | spin_unlock_irqrestore(&info->lock,flags); | ||
3195 | 3206 | ||
3196 | if (!(info->port.flags & ASYNC_CLOSING) && | 3207 | if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd )) |
3197 | (do_clocal || (info->signals & SerialSignal_DCD)) ) { | ||
3198 | break; | 3208 | break; |
3199 | } | ||
3200 | 3209 | ||
3201 | if (signal_pending(current)) { | 3210 | if (signal_pending(current)) { |
3202 | retval = -ERESTARTSYS; | 3211 | retval = -ERESTARTSYS; |
@@ -3208,14 +3217,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
3208 | } | 3217 | } |
3209 | 3218 | ||
3210 | set_current_state(TASK_RUNNING); | 3219 | set_current_state(TASK_RUNNING); |
3211 | remove_wait_queue(&info->port.open_wait, &wait); | 3220 | remove_wait_queue(&port->open_wait, &wait); |
3212 | 3221 | ||
3213 | if (extra_count) | 3222 | if (extra_count) |
3214 | info->port.count++; | 3223 | port->count++; |
3215 | info->port.blocked_open--; | 3224 | port->blocked_open--; |
3216 | 3225 | ||
3217 | if (!retval) | 3226 | if (!retval) |
3218 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 3227 | port->flags |= ASYNC_NORMAL_ACTIVE; |
3219 | 3228 | ||
3220 | DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); | 3229 | DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); |
3221 | return retval; | 3230 | return retval; |
@@ -3444,6 +3453,10 @@ static void add_device(struct slgt_info *info) | |||
3444 | #endif | 3453 | #endif |
3445 | } | 3454 | } |
3446 | 3455 | ||
3456 | static const struct tty_port_operations slgt_port_ops = { | ||
3457 | .carrier_raised = carrier_raised, | ||
3458 | }; | ||
3459 | |||
3447 | /* | 3460 | /* |
3448 | * allocate device instance structure, return NULL on failure | 3461 | * allocate device instance structure, return NULL on failure |
3449 | */ | 3462 | */ |
@@ -3458,6 +3471,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev | |||
3458 | driver_name, adapter_num, port_num)); | 3471 | driver_name, adapter_num, port_num)); |
3459 | } else { | 3472 | } else { |
3460 | tty_port_init(&info->port); | 3473 | tty_port_init(&info->port); |
3474 | info->port.ops = &slgt_port_ops; | ||
3461 | info->magic = MGSL_MAGIC; | 3475 | info->magic = MGSL_MAGIC; |
3462 | INIT_WORK(&info->task, bh_handler); | 3476 | INIT_WORK(&info->task, bh_handler); |
3463 | info->max_frame_size = 4096; | 3477 | info->max_frame_size = 4096; |