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.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.c')
-rw-r--r-- | drivers/char/synclink.c | 61 |
1 files changed, 41 insertions, 20 deletions
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 500f5176b6ba..fb2e6b5e0ef1 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c | |||
@@ -3281,6 +3281,23 @@ static void mgsl_hangup(struct tty_struct *tty) | |||
3281 | 3281 | ||
3282 | } /* end of mgsl_hangup() */ | 3282 | } /* end of mgsl_hangup() */ |
3283 | 3283 | ||
3284 | /* | ||
3285 | * carrier_raised() | ||
3286 | * | ||
3287 | * Return true if carrier is raised | ||
3288 | */ | ||
3289 | |||
3290 | static int carrier_raised(struct tty_port *port) | ||
3291 | { | ||
3292 | unsigned long flags; | ||
3293 | struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); | ||
3294 | |||
3295 | spin_lock_irqsave(&info->irq_spinlock, flags); | ||
3296 | usc_get_serial_signals(info); | ||
3297 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | ||
3298 | return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; | ||
3299 | } | ||
3300 | |||
3284 | /* block_til_ready() | 3301 | /* block_til_ready() |
3285 | * | 3302 | * |
3286 | * Block the current process until the specified port | 3303 | * Block the current process until the specified port |
@@ -3302,6 +3319,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3302 | bool do_clocal = false; | 3319 | bool do_clocal = false; |
3303 | bool extra_count = false; | 3320 | bool extra_count = false; |
3304 | unsigned long flags; | 3321 | unsigned long flags; |
3322 | int dcd; | ||
3323 | struct tty_port *port = &info->port; | ||
3305 | 3324 | ||
3306 | if (debug_level >= DEBUG_LEVEL_INFO) | 3325 | if (debug_level >= DEBUG_LEVEL_INFO) |
3307 | printk("%s(%d):block_til_ready on %s\n", | 3326 | printk("%s(%d):block_til_ready on %s\n", |
@@ -3309,7 +3328,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3309 | 3328 | ||
3310 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ | 3329 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ |
3311 | /* nonblock mode is set or port is not enabled */ | 3330 | /* nonblock mode is set or port is not enabled */ |
3312 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 3331 | port->flags |= ASYNC_NORMAL_ACTIVE; |
3313 | return 0; | 3332 | return 0; |
3314 | } | 3333 | } |
3315 | 3334 | ||
@@ -3318,25 +3337,25 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3318 | 3337 | ||
3319 | /* Wait for carrier detect and the line to become | 3338 | /* Wait for carrier detect and the line to become |
3320 | * free (i.e., not in use by the callout). While we are in | 3339 | * free (i.e., not in use by the callout). While we are in |
3321 | * this loop, info->port.count is dropped by one, so that | 3340 | * this loop, port->count is dropped by one, so that |
3322 | * mgsl_close() knows when to free things. We restore it upon | 3341 | * mgsl_close() knows when to free things. We restore it upon |
3323 | * exit, either normal or abnormal. | 3342 | * exit, either normal or abnormal. |
3324 | */ | 3343 | */ |
3325 | 3344 | ||
3326 | retval = 0; | 3345 | retval = 0; |
3327 | add_wait_queue(&info->port.open_wait, &wait); | 3346 | add_wait_queue(&port->open_wait, &wait); |
3328 | 3347 | ||
3329 | if (debug_level >= DEBUG_LEVEL_INFO) | 3348 | if (debug_level >= DEBUG_LEVEL_INFO) |
3330 | printk("%s(%d):block_til_ready before block on %s count=%d\n", | 3349 | printk("%s(%d):block_til_ready before block on %s count=%d\n", |
3331 | __FILE__,__LINE__, tty->driver->name, info->port.count ); | 3350 | __FILE__,__LINE__, tty->driver->name, port->count ); |
3332 | 3351 | ||
3333 | spin_lock_irqsave(&info->irq_spinlock, flags); | 3352 | spin_lock_irqsave(&info->irq_spinlock, flags); |
3334 | if (!tty_hung_up_p(filp)) { | 3353 | if (!tty_hung_up_p(filp)) { |
3335 | extra_count = true; | 3354 | extra_count = true; |
3336 | info->port.count--; | 3355 | port->count--; |
3337 | } | 3356 | } |
3338 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | 3357 | spin_unlock_irqrestore(&info->irq_spinlock, flags); |
3339 | info->port.blocked_open++; | 3358 | port->blocked_open++; |
3340 | 3359 | ||
3341 | while (1) { | 3360 | while (1) { |
3342 | if (tty->termios->c_cflag & CBAUD) { | 3361 | if (tty->termios->c_cflag & CBAUD) { |
@@ -3348,20 +3367,16 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3348 | 3367 | ||
3349 | set_current_state(TASK_INTERRUPTIBLE); | 3368 | set_current_state(TASK_INTERRUPTIBLE); |
3350 | 3369 | ||
3351 | if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ | 3370 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ |
3352 | retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? | 3371 | retval = (port->flags & ASYNC_HUP_NOTIFY) ? |
3353 | -EAGAIN : -ERESTARTSYS; | 3372 | -EAGAIN : -ERESTARTSYS; |
3354 | break; | 3373 | break; |
3355 | } | 3374 | } |
3356 | 3375 | ||
3357 | spin_lock_irqsave(&info->irq_spinlock,flags); | 3376 | dcd = tty_port_carrier_raised(&info->port); |
3358 | usc_get_serial_signals(info); | ||
3359 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3360 | 3377 | ||
3361 | if (!(info->port.flags & ASYNC_CLOSING) && | 3378 | if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd)) |
3362 | (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { | ||
3363 | break; | 3379 | break; |
3364 | } | ||
3365 | 3380 | ||
3366 | if (signal_pending(current)) { | 3381 | if (signal_pending(current)) { |
3367 | retval = -ERESTARTSYS; | 3382 | retval = -ERESTARTSYS; |
@@ -3370,24 +3385,24 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3370 | 3385 | ||
3371 | if (debug_level >= DEBUG_LEVEL_INFO) | 3386 | if (debug_level >= DEBUG_LEVEL_INFO) |
3372 | printk("%s(%d):block_til_ready blocking on %s count=%d\n", | 3387 | printk("%s(%d):block_til_ready blocking on %s count=%d\n", |
3373 | __FILE__,__LINE__, tty->driver->name, info->port.count ); | 3388 | __FILE__,__LINE__, tty->driver->name, port->count ); |
3374 | 3389 | ||
3375 | schedule(); | 3390 | schedule(); |
3376 | } | 3391 | } |
3377 | 3392 | ||
3378 | set_current_state(TASK_RUNNING); | 3393 | set_current_state(TASK_RUNNING); |
3379 | remove_wait_queue(&info->port.open_wait, &wait); | 3394 | remove_wait_queue(&port->open_wait, &wait); |
3380 | 3395 | ||
3381 | if (extra_count) | 3396 | if (extra_count) |
3382 | info->port.count++; | 3397 | port->count++; |
3383 | info->port.blocked_open--; | 3398 | port->blocked_open--; |
3384 | 3399 | ||
3385 | if (debug_level >= DEBUG_LEVEL_INFO) | 3400 | if (debug_level >= DEBUG_LEVEL_INFO) |
3386 | printk("%s(%d):block_til_ready after blocking on %s count=%d\n", | 3401 | printk("%s(%d):block_til_ready after blocking on %s count=%d\n", |
3387 | __FILE__,__LINE__, tty->driver->name, info->port.count ); | 3402 | __FILE__,__LINE__, tty->driver->name, port->count ); |
3388 | 3403 | ||
3389 | if (!retval) | 3404 | if (!retval) |
3390 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 3405 | port->flags |= ASYNC_NORMAL_ACTIVE; |
3391 | 3406 | ||
3392 | return retval; | 3407 | return retval; |
3393 | 3408 | ||
@@ -4304,6 +4319,11 @@ static void mgsl_add_device( struct mgsl_struct *info ) | |||
4304 | 4319 | ||
4305 | } /* end of mgsl_add_device() */ | 4320 | } /* end of mgsl_add_device() */ |
4306 | 4321 | ||
4322 | static const struct tty_port_operations mgsl_port_ops = { | ||
4323 | .carrier_raised = carrier_raised, | ||
4324 | }; | ||
4325 | |||
4326 | |||
4307 | /* mgsl_allocate_device() | 4327 | /* mgsl_allocate_device() |
4308 | * | 4328 | * |
4309 | * Allocate and initialize a device instance structure | 4329 | * Allocate and initialize a device instance structure |
@@ -4322,6 +4342,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) | |||
4322 | printk("Error can't allocate device instance data\n"); | 4342 | printk("Error can't allocate device instance data\n"); |
4323 | } else { | 4343 | } else { |
4324 | tty_port_init(&info->port); | 4344 | tty_port_init(&info->port); |
4345 | info->port.ops = &mgsl_port_ops; | ||
4325 | info->magic = MGSL_MAGIC; | 4346 | info->magic = MGSL_MAGIC; |
4326 | INIT_WORK(&info->task, mgsl_bh_handler); | 4347 | INIT_WORK(&info->task, mgsl_bh_handler); |
4327 | info->max_frame_size = 4096; | 4348 | info->max_frame_size = 4096; |