#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
#define NR_PORTS 64 /* maximum number of ports */
#define NR_PRIMARY 8 /* maximum number of primary ports */
-#define REGION_SIZE 8 /* size of io region to request */
/* The following variables can be set by giving module options */
static int irq[NR_PRIMARY]; /* IRQ for each base port */
MODULE_LICENSE("GPL");
-module_param_array(irq, int, NULL, 0);
-module_param_array(divisor, uint, NULL, 0);
-module_param(dma, uint, 0);
-module_param(rx_trigger, uint, 0);
-module_param(tx_trigger, uint, 0);
-module_param(flow_off, uint, 0);
-module_param(flow_on, uint, 0);
-module_param(rx_timeout, uint, 0);
-module_param(pio_threshold, uint, 0);
+MODULE_PARM(irq, "1-8i");
+MODULE_PARM(divisor, "1-8i");
+MODULE_PARM(dma, "i");
+MODULE_PARM(rx_trigger, "i");
+MODULE_PARM(tx_trigger, "i");
+MODULE_PARM(flow_off, "i");
+MODULE_PARM(flow_on, "i");
+MODULE_PARM(rx_timeout, "i");
+MODULE_PARM(pio_threshold, "i");
/* END */
restore_flags(flags);
}
-static int rs_write(struct tty_struct * tty,
+static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
int c, t, ret = 0;
if (!tty || !info->xmit_buf || !tmp_buf)
return 0;
+ if (from_user)
+ down(&tmp_buf_sem);
+
while (1) {
/* Thanks to R. Wolff for suggesting how to do this with */
/* interrupts enabled */
if (c <= 0)
break;
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ if (from_user) {
+ c -= copy_from_user(tmp_buf, buf, c);
+
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1);
info->xmit_cnt += c;
ret += c;
}
+ if (from_user)
+ up(&tmp_buf_sem);
+
save_flags(flags); cli();
if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
if (info->blocked_open) {
if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(info->close_delay);
}
wake_up_interruptible(&info->open_wait);
}
while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
(serial_in(info, UART_ESI_STAT2) != 0xff)) {
- msleep_interruptible(jiffies_to_msecs(char_time));
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(char_time);
if (signal_pending(current))
break;
* This routine is called by espserial_init() to initialize a specific serial
* port.
*/
-static _INLINE_ int autoconfig(struct esp_struct * info)
+static _INLINE_ int autoconfig(struct esp_struct * info, int *region_start)
{
int port_detected = 0;
unsigned long flags;
- if (!request_region(info->port, REGION_SIZE, "esp serial"))
- return -EIO;
-
save_flags(flags); cli();
/*
* Check for ESP card
*/
- if (serial_in(info, UART_ESI_BASE) == 0xf3) {
+ if (!check_region(info->port, 8) &&
+ serial_in(info, UART_ESI_BASE) == 0xf3) {
serial_out(info, UART_ESI_CMD1, 0x00);
serial_out(info, UART_ESI_CMD1, 0x01);
info->irq = 4;
}
+ if (ports && (ports->port == (info->port - 8))) {
+ release_region(*region_start,
+ info->port - *region_start);
+ } else
+ *region_start = info->port;
+
+ if (!request_region(*region_start,
+ info->port - *region_start + 8,
+ "esp serial"))
+ {
+ restore_flags(flags);
+ return -EIO;
+ }
/* put card in enhanced mode */
/* this prevents access through */
serial_out(info, UART_ESI_CMD2, 0x00);
}
}
- if (!port_detected)
- release_region(info->port, REGION_SIZE);
restore_flags(flags);
return (port_detected);
int __init espserial_init(void)
{
int i, offset;
+ int region_start;
struct esp_struct * info;
struct esp_struct *last_primary = NULL;
int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
info->irq = irq[i];
info->line = (i * 8) + (offset / 8);
- if (!autoconfig(info)) {
+ if (!autoconfig(info, ®ion_start)) {
i++;
offset = 0;
continue;
{
unsigned long flags;
int e1;
+ unsigned int region_start, region_end;
struct esp_struct *temp_async;
struct esp_pio_buffer *pio_buf;
while (ports) {
if (ports->port) {
- release_region(ports->port, REGION_SIZE);
+ region_start = region_end = ports->port;
+ temp_async = ports;
+
+ while (temp_async) {
+ if ((region_start - temp_async->port) == 8) {
+ region_start = temp_async->port;
+ temp_async->port = 0;
+ temp_async = ports;
+ } else if ((temp_async->port - region_end)
+ == 8) {
+ region_end = temp_async->port;
+ temp_async->port = 0;
+ temp_async = ports;
+ } else
+ temp_async = temp_async->next_port;
+ }
+
+ release_region(region_start,
+ region_end - region_start + 8);
}
+
temp_async = ports->next_port;
kfree(ports);
ports = temp_async;