patch-2.3.16 linux/drivers/macintosh/macserial.c
Next file: linux/drivers/macintosh/mediabay.c
Previous file: linux/drivers/macintosh/macio-adb.c
Back to the patch index
Back to the overall index
- Lines: 463
- Date:
Tue Aug 31 11:35:59 1999
- Orig file:
v2.3.15/linux/drivers/macintosh/macserial.c
- Orig date:
Thu Aug 12 11:50:14 1999
diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
@@ -9,6 +9,7 @@
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -26,6 +27,7 @@
#include <linux/console.h>
#endif
+#include <asm/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -135,13 +137,13 @@
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
-static unsigned char tmp_buf[4096]; /* This is cheating */
-DECLARE_MUTEX(tmp_buf_sem);
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
static inline int __pmac
serial_paranoia_check(struct mac_serial *info,
- dev_t device, const char *routine)
+ dev_t device, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
@@ -165,7 +167,7 @@
* Reading and writing Z8530 registers.
*/
static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel,
- unsigned char reg)
+ unsigned char reg)
{
unsigned char retval;
unsigned long flags;
@@ -185,7 +187,7 @@
}
static inline void __pmac write_zsreg(struct mac_zschannel *channel,
- unsigned char reg, unsigned char value)
+ unsigned char reg, unsigned char value)
{
unsigned long flags;
@@ -357,8 +359,12 @@
static void transmit_chars(struct mac_serial *info)
{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
- return;
+ goto out;
info->tx_active = 0;
if (info->x_char) {
@@ -366,12 +372,12 @@
write_zsdata(info->zs_channel, info->x_char);
info->x_char = 0;
info->tx_active = 1;
- return;
+ goto out;
}
if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
write_zsreg(info->zs_channel, 0, RES_Tx_P);
- return;
+ goto out;
}
/* Send char */
@@ -382,6 +388,9 @@
if (info->xmit_cnt < WAKEUP_CHARS)
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+ out:
+ restore_flags(flags);
}
static _INLINE_ void status_handle(struct mac_serial *info)
@@ -764,8 +773,10 @@
*/
mdelay(250);
}
+#ifdef CONFIG_PMAC_PBOOK
if (info->is_pwbk_ir)
pmu_enable_irled(1);
+#endif /* CONFIG_PMAC_PBOOK */
} else {
#ifdef SERIAL_DEBUG_POWER
printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line);
@@ -795,8 +806,10 @@
feature_clear(info->dev_node, FEATURE_Modem_Reset);
mdelay(25);
}
+#ifdef CONFIG_PMAC_PBOOK
if (info->is_pwbk_ir)
pmu_enable_irled(0);
+#endif /* CONFIG_PMAC_PBOOK */
if (info->zs_chan_a == info->zs_channel) {
#ifdef SERIAL_DEBUG_POWER
@@ -987,7 +1000,6 @@
static void rs_flush_chars(struct tty_struct *tty)
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
@@ -997,53 +1009,76 @@
return;
/* Enable transmitter */
- save_flags(flags); cli();
transmit_chars(info);
- restore_flags(flags);
}
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
- int c, total = 0;
+ int c, ret = 0;
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf)
+ if (!tty || !info->xmit_buf || !tmp_buf)
return 0;
save_flags(flags);
- while (1) {
- cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
-
- if (from_user) {
- down(&tmp_buf_sem);
- copy_from_user(tmp_buf, buf, c);
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ cli();
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
- } else
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
}
if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
&& !info->tx_active)
transmit_chars(info);
restore_flags(flags);
- return total;
+ return ret;
}
static int rs_write_room(struct tty_struct *tty)
@@ -1186,7 +1221,9 @@
tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
}
static int set_serial_info(struct mac_serial * info,
@@ -1196,9 +1233,8 @@
struct mac_serial old_info;
int retval = 0;
- if (!new_info)
+ if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
old_info = *info;
if (!capable(CAP_SYS_ADMIN)) {
@@ -1248,29 +1284,30 @@
static int get_lsr_info(struct mac_serial * info, unsigned int *value)
{
unsigned char status;
+ unsigned long flags;
- cli();
+ save_flags(flags); cli();
status = read_zsreg(info->zs_channel, 0);
- sti();
- put_user(status,value);
- return 0;
+ restore_flags(flags);
+ status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
+ return put_user(status,value);
}
static int get_modem_info(struct mac_serial *info, unsigned int *value)
{
unsigned char control, status;
unsigned int result;
+ unsigned long flags;
- cli();
+ save_flags(flags); cli();
control = info->curregs[5];
status = read_zsreg(info->zs_channel, 0);
- sti();
+ restore_flags(flags);
result = ((control & RTS) ? TIOCM_RTS: 0)
| ((control & DTR) ? TIOCM_DTR: 0)
| ((status & DCD) ? TIOCM_CAR: 0)
| ((status & CTS) ? 0: TIOCM_CTS);
- put_user(result,value);
- return 0;
+ return put_user(result,value);
}
static int set_modem_info(struct mac_serial *info, unsigned int cmd,
@@ -1278,13 +1315,13 @@
{
int error;
unsigned int arg, bits;
+ unsigned long flags;
- error = verify_area(VERIFY_READ, value, sizeof(int));
+ error = get_user(arg, value);
if (error)
return error;
- get_user(arg, value);
bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
- cli();
+ save_flags(flags); cli();
switch (cmd) {
case TIOCMBIS:
info->curregs[5] |= bits;
@@ -1296,12 +1333,12 @@
info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
break;
default:
- sti();
+ restore_flags(flags);
return -EINVAL;
}
info->pendregs[5] = info->curregs[5];
write_zsreg(info->zs_channel, 5, info->curregs[5]);
- sti();
+ restore_flags(flags);
return 0;
}
@@ -1330,7 +1367,6 @@
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct mac_serial * info = (struct mac_serial *)tty->driver_data;
#ifdef CONFIG_KGDB
@@ -1341,48 +1377,31 @@
return -ENODEV;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
switch (cmd) {
case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
return set_modem_info(info, cmd, (unsigned int *) arg);
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
return get_serial_info(info,
(struct serial_struct *) arg);
case TIOCSSERIAL:
return set_serial_info(info,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return get_lsr_info(info, (unsigned int *) arg);
+ return get_lsr_info(info, (unsigned int *) arg);
case TIOCSERGSTRUCT:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct mac_serial));
- if (error)
- return error;
- copy_from_user((struct mac_serial *) arg,
- info, sizeof(struct mac_serial));
+ if (copy_to_user((struct mac_serial *) arg,
+ info, sizeof(struct mac_serial)))
+ return -EFAULT;
return 0;
default:
@@ -1674,7 +1693,7 @@
(tty->termios->c_cflag & CBAUD))
zs_rtsdtr(info, 1);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ZILOG_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
@@ -1726,6 +1745,7 @@
{
struct mac_serial *info;
int retval, line;
+ unsigned long page;
line = MINOR(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= zs_channels_found))
@@ -1747,6 +1767,16 @@
tty->driver_data = info;
info->tty = tty;
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ }
+
/*
* If the port is the middle of closing, bail out now
*/
@@ -1817,6 +1847,7 @@
struct device_node *dev, *ch;
struct mac_serial **pp;
int n, lenp;
+ char *conn;
n = 0;
pp = &zs_chain;
@@ -1842,9 +1873,11 @@
zs_soft[n].zs_channel->parent = &zs_soft[n];
zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
- /* XXX tested only with wallstreet PowerBook, should do no harm anyway */
- zs_soft[n].is_pwbk_ir = (strcmp(get_property(ch, "AAPL,connector",
- &lenp), "infrared") == 0);
+ /* XXX tested only with wallstreet PowerBook,
+ should do no harm anyway */
+ conn = get_property(ch, "AAPL,connector", &lenp);
+ zs_soft[n].is_pwbk_ir =
+ conn && (strcmp(conn, "infrared") == 0);
/* XXX this assumes the prom puts chan A before B */
if (n & 1)
@@ -2024,6 +2057,30 @@
return 0;
}
+
+#ifdef MODULE
+int init_module(void)
+{
+ macserial_init();
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int i;
+ unsigned long flags;
+ struct mac_serial *info;
+
+ for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+ set_scc_power(info, 0);
+ save_flags(flags); cli();
+ for (i = 0; i < zs_channels_found; ++i)
+ free_irq(zs_soft[i].irq, &zs_soft[i]);
+ restore_flags(flags);
+ tty_unregister_driver(&callout_driver);
+ tty_unregister_driver(&serial_driver);
+}
+#endif /* MODULE */
#if 0
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)