diff options
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/Makefile | 7 | ||||
-rw-r--r-- | drivers/macintosh/adb.c | 26 | ||||
-rw-r--r-- | drivers/macintosh/mac_keyb.c | 170 | ||||
-rw-r--r-- | drivers/macintosh/macio-adb.c | 23 | ||||
-rw-r--r-- | drivers/macintosh/macserial.c | 89 | ||||
-rw-r--r-- | drivers/macintosh/macserial.h | 3 | ||||
-rw-r--r-- | drivers/macintosh/mediabay.c | 308 | ||||
-rw-r--r-- | drivers/macintosh/via-cuda.c | 20 | ||||
-rw-r--r-- | drivers/macintosh/via-pmu.c | 102 |
9 files changed, 518 insertions, 230 deletions
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 6ab7eba3a..74086d99b 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -16,14 +16,15 @@ L_TARGET := macintosh.a M_OBJS := ifndef CONFIG_MBX -L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o +L_OBJS := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o +LX_OBJS := adb.o endif ifeq ($(CONFIG_MAC_SERIAL),y) - LX_OBJS += macserial.o + L_OBJS += macserial.o else ifeq ($(CONFIG_MAC_SERIAL),m) - MX_OBJS += macserial.o + M_OBJS += macserial.o endif endif diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 4c9a67cc0..4bcd1715b 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -8,6 +8,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/malloc.h> +#include <linux/module.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/sched.h> @@ -19,10 +20,13 @@ #include <asm/hydra.h> #include <asm/init.h> +EXPORT_SYMBOL(adb_hardware); + enum adb_hw adb_hardware = ADB_NONE; int (*adb_send_request)(struct adb_request *req, int sync); -int (*adb_autopoll)(int on); -static void adb_scan_bus(void); +int (*adb_autopoll)(int devs); +int (*adb_reset_bus)(void); +static int adb_scan_bus(void); static struct adb_handler { void (*handler)(unsigned char *, int, struct pt_regs *, int); @@ -50,13 +54,13 @@ static void printADBreply(struct adb_request *req) } #endif -static void adb_scan_bus(void) +static int adb_scan_bus(void) { int i, highFree=0, noMovement; + int devmask = 0; struct adb_request req; - /* reset ADB bus */ - /*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/ + adb_reset_bus(); /* reset ADB bus */ /* assumes adb_handler[] is all zeroes at this point */ for (i = 1; i < 16; i++) { @@ -134,24 +138,27 @@ static void adb_scan_bus(void) adb_handler[i].handler_id = req.reply[2]; printk(" [%d]: %d %x", i, adb_handler[i].original_address, adb_handler[i].handler_id); + devmask |= 1 << i; } printk("\n"); + return devmask; } void adb_init(void) { adb_send_request = (void *) adb_nodev; adb_autopoll = (void *) adb_nodev; + adb_reset_bus = adb_nodev; if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; via_cuda_init(); via_pmu_init(); macio_adb_init(); if (adb_hardware == ADB_NONE) printk(KERN_WARNING "Warning: no ADB interface detected\n"); else { - adb_scan_bus(); - adb_autopoll(1); + int devs = adb_scan_bus(); + adb_autopoll(devs); } } @@ -187,8 +194,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids, ids->nids = 0; for (i = 1; i < 16; i++) { - if ((adb_handler[i].original_address == default_id) || - (adb_handler[i].handler_id == handler_id)) { + if (adb_handler[i].original_address == default_id) { if (adb_handler[i].handler != 0) { printk(KERN_ERR "Two handlers for ADB device %d\n", diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 5c49af36f..c2ff83b83 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -16,6 +16,8 @@ #include <linux/signal.h> #include <linux/ioport.h> #include <linux/init.h> +#include <linux/tty_flip.h> +#include <linux/config.h> #include <asm/bitops.h> #include <asm/adb.h> @@ -170,16 +172,22 @@ static int last_keycode; static void keyboard_input(unsigned char *, int, struct pt_regs *, int); static void input_keycode(int, int); static void leds_done(struct adb_request *); +static void mac_put_queue(int); +#ifdef CONFIG_ADBMOUSE /* XXX: Hook for mouse driver */ -void (*adb_mouse_interrupt_hook) (char *, int); -static int adb_emulate_buttons = 0; +void (*adb_mouse_interrupt_hook)(unsigned char *, int); +int adb_emulate_buttons = 0; +int adb_button2_keycode = 0x7d; /* right control key */ +int adb_button3_keycode = 0x7c; /* right option key */ +#endif + extern int console_loglevel; extern struct kbd_struct kbd_table[]; +extern struct wait_queue * keypress_wait; extern void handle_scancode(unsigned char); -extern void put_queue(int); static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; @@ -264,6 +272,7 @@ input_keycode(int keycode, int repeat) if (!repeat) del_timer(&repeat_timer); +#ifdef CONFIG_ADBMOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. * Keep track of 'button' states here as we only send @@ -273,52 +282,27 @@ input_keycode(int keycode, int repeat) * Might also want to know how many buttons need to be emulated. * -> hide this as function in arch/m68k/mac ? */ - if ( (adb_emulate_buttons) && - (adb_mouse_interrupt_hook || console_loglevel == 10) ) { - unsigned char button, button2, button3, fake_event; - static unsigned char button2state=0, button3state=0; /* up */ + if (adb_emulate_buttons + && (keycode == adb_button2_keycode + || keycode == adb_button3_keycode) + && (adb_mouse_interrupt_hook || console_loglevel == 10)) { + int button; /* faked ADB packet */ - static char data[4] = { 0, 0x80, 0x80, 0x80 }; - - button = 0; - fake_event = 0; - switch (keycode) { /* which 'button' ? */ - case 0x7c: /* R-option */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - break; - case 0x7d: /* R-control */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - break; - } - if (fake_event && console_loglevel >= 8) - printk("fake event: button2 %d button3 %d button %d\n", - button2state, button3state, button); - if (button) { /* there's been a button state change */ - /* fake a mouse packet : send all bytes, change one! */ - data[button] = (up_flag ? 0x80 : 0); + static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; + + button = keycode == adb_button2_keycode? 2: 3; + if (data[button] != up_flag) { + /* send a fake mouse packet */ + data[button] = up_flag; + if (console_loglevel >= 8) + printk("fake mouse event: %x %x %x\n", + data[1], data[2], data[3]); if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, -1); - else - printk("mouse_fake: data %x %x %x buttons %x \n", - data[1], data[2], data[3], - ~( (data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2) )&7 ); + adb_mouse_interrupt_hook(data, 4); } - /* - * XXX: testing mouse emulation ... don't process fake keys! - */ - if (fake_event) - return; + return; } +#endif /* CONFIG_ADBMOUSE */ if (kbd->kbdmode != VC_RAW) { if (!up_flag && !dont_repeat[keycode]) { @@ -361,6 +345,20 @@ kbd_repeat(unsigned long xxx) restore_flags(flags); } +static void mac_put_queue(int ch) +{ + extern struct tty_driver console_driver; + struct tty_struct *tty; + + tty = console_driver.table? console_driver.table[fg_console]: NULL; + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } +} + +#ifdef CONFIG_ADBMOUSE static void mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { @@ -399,62 +397,34 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) */ /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx First button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + Handler 4 -- Apple Extended mouse protocol. For Apple's 3-button mouse protocol the data array will contain the following values: BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. Y is additional + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + data[3] = byyy bxxx Third button and fourth button. Y is additional high bits of y-axis motion. XY is additional high bits of x-axis motion. - - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - - NOTE: data[0] is confirmed by the parent function and need not be - checked here. */ struct kbd_struct *kbd; if (adb_mouse_interrupt_hook) adb_mouse_interrupt_hook(data, nb); - else - if (console_loglevel == 10) - printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", - data[1], data[2], data[3], - ~((data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2))&7, - ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ), - ((data[1]&0x7f) < 64 ? -(data[1]&0x7f) : 128-(data[1]&0x7f) ) ); kbd = kbd_table + fg_console; @@ -464,9 +434,9 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) unsigned char uchButtonSecond; /* Send first button, second button and movement. */ - put_queue( 0x7e ); - put_queue( data[1] ); - put_queue( data[2] ); + mac_put_queue(0x7e); + mac_put_queue(data[1]); + mac_put_queue(data[2]); /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ @@ -475,12 +445,12 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) /* Send second button. */ if (uchButtonSecond != uch_ButtonStateSecond) { - put_queue( 0x3f | uchButtonSecond ); + mac_put_queue(0x3f | uchButtonSecond); uch_ButtonStateSecond = uchButtonSecond; } /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 4) && autopoll /*?*/) { + if (nb == 4) { static unsigned char uch_ButtonStateThird = 0x80; unsigned char uchButtonThird; @@ -489,12 +459,13 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) /* Send third button. */ if (uchButtonThird != uch_ButtonStateThird) { - put_queue( 0x40 | uchButtonThird ); + mac_put_queue(0x40 | uchButtonThird); uch_ButtonStateThird = uchButtonThird; } } } } +#endif /* CONFIG_ADBMOUSE */ /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ static unsigned char mac_ledmap[8] = { @@ -571,11 +542,14 @@ __initfunc(void mackbd_init_hw(void)) memcpy(key_maps[8], macalt_map, sizeof(plain_map)); memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map)); +#ifdef CONFIG_ADBMOUSE /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; - adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input); +#endif /* CONFIG_ADBMOUSE */ + + adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); for(i = 0; i < keyboard_ids.nids; i++) { /* turn off all leds */ @@ -634,9 +608,3 @@ __initfunc(void mackbd_init_hw(void)) } } } - -void adb_setup_mouse( char *s, int *ints ) -{ - if (ints[0] >= 1) - adb_emulate_buttons = ints[1]; -} diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 0af447c08..b3e7b0ec2 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -61,8 +61,9 @@ static unsigned char adb_rbuf[16]; static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs); static int macio_adb_send_request(struct adb_request *req, int sync); -static int macio_adb_autopoll(int on); +static int macio_adb_autopoll(int devs); static void macio_adb_poll(void); +static int macio_reset_bus(void); static void completed(void); __openfirmware @@ -108,14 +109,30 @@ void macio_adb_init(void) adb_hardware = ADB_MACIO; adb_send_request = macio_adb_send_request; adb_autopoll = macio_adb_autopoll; + adb_reset_bus = macio_reset_bus; } -static int macio_adb_autopoll(int on) +static int macio_adb_autopoll(int devs) { - out_8(&adb->autopoll.r, on? APE: 0); + out_8(&adb->active_hi.r, devs >> 8); + out_8(&adb->active_lo.r, devs); + out_8(&adb->autopoll.r, devs? APE: 0); return 0; } +static int macio_reset_bus(void) +{ + int timeout = 1000000; + + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST); + while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) { + if (--timeout == 0) { + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST); + return -1; + } + } + return 0; +} /* Send an ADB command */ static int macio_adb_send_request(struct adb_request *req, int sync) diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 7c8cf23d8..5af8ad871 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -33,6 +33,7 @@ #include <asm/system.h> #include <asm/segment.h> #include <asm/bitops.h> +#include <asm/feature.h> #ifdef CONFIG_KGDB #include <asm/kgdb.h> #endif @@ -165,25 +166,35 @@ static inline unsigned char read_zsreg(struct mac_zschannel *channel, unsigned char reg) { unsigned char retval; + unsigned long flags; + /* + * We have to make this atomic. + */ + spin_lock_irqsave(&channel->lock, flags); if (reg != 0) { *channel->control = reg; RECOVERY_DELAY; } retval = *channel->control; RECOVERY_DELAY; + spin_unlock_irqrestore(&channel->lock, flags); return retval; } static inline void write_zsreg(struct mac_zschannel *channel, unsigned char reg, unsigned char value) { + unsigned long flags; + + spin_lock_irqsave(&channel->lock, flags); if (reg != 0) { *channel->control = reg; RECOVERY_DELAY; } *channel->control = value; RECOVERY_DELAY; + spin_unlock_irqrestore(&channel->lock, flags); return; } @@ -434,6 +445,10 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) for (;;) { zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; +#ifdef SERIAL_DEBUG_INTR +// printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg); +#endif + if ((zs_intreg & CHAN_IRQMASK) == 0) break; @@ -1261,17 +1276,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty->closing = 0; info->event = 0; info->tty = 0; + + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } + if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); + restore_flags(flags); } @@ -1301,8 +1325,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) @@ -1510,9 +1533,25 @@ static int rs_open(struct tty_struct *tty, struct file * filp) /* * Start up serial port */ + + if (info->is_cobalt_modem) { + /* Power up modem */ + feature_set(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(250); + feature_clear(info->dev_node, FEATURE_Modem_Reset); + mdelay(10); + } retval = startup(info); - if (retval) + if (retval) { + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } return retval; + } retval = block_til_ready(tty, filp, info); if (retval) { @@ -1520,6 +1559,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp) printk("rs_open returning after block_til_ready with %d\n", retval); #endif + if (info->is_cobalt_modem) { + /* Power down modem */ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_PowerOn); + mdelay(15); + } return retval; } @@ -1570,8 +1616,14 @@ probe_sccs() dev->full_name); continue; } + feature_clear(dev, FEATURE_Serial_reset); + mdelay(5); + feature_set(dev, FEATURE_Serial_enable); + feature_set(dev, FEATURE_Serial_IO_A); + feature_set(dev, FEATURE_Serial_IO_B); + mdelay(5); for (ch = dev->child; ch != 0; ch = ch->sibling) { - if (ch->n_addrs < 1 || ch ->n_intrs < 1) { + if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) { printk("Can't use %s: %d addrs %d intrs\n", ch->full_name, ch->n_addrs, ch->n_intrs); continue; @@ -1580,8 +1632,20 @@ probe_sccs() ioremap(ch->addrs[0].address, 0x1000); zs_channels[n].data = zs_channels[n].control + ch->addrs[0].size / 2; + spin_lock_init(&zs_channels[n].lock); zs_soft[n].zs_channel = &zs_channels[n]; + zs_soft[n].dev_node = ch; zs_soft[n].irq = ch->intrs[0].line; + zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt"); + if (zs_soft[n].is_cobalt_modem) + { + /* Just in case the modem is up, shut it down */ + feature_set(ch, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(ch, FEATURE_Modem_PowerOn); + mdelay(15); + } + /* XXX this assumes the prom puts chan A before B */ if (n & 1) zs_soft[n].zs_chan_a = &zs_channels[n-1]; @@ -1698,6 +1762,9 @@ int macserial_init(void) for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { + unsigned char* connector; + int lenp; + #ifdef CONFIG_KGDB if (info->kgdb_channel) { continue; @@ -1721,8 +1788,14 @@ int macserial_init(void) info->open_wait = 0; info->close_wait = 0; printk("tty%02d at 0x%08x (irq = %d)", info->line, - info->port, info->irq); - printk(" is a Z8530 ESCC\n"); + info->port, info->irq); + printk(" is a Z8530 ESCC"); + connector = get_property(info->dev_node, "AAPL,connector", &lenp); + if (connector) + printk(", port = %s", connector); + if (info->is_cobalt_modem) + printk(" (cobalt modem)"); + printk("\n"); } restore_flags(flags); diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h index 83e6dc932..ec7552f96 100644 --- a/drivers/macintosh/macserial.h +++ b/drivers/macintosh/macserial.h @@ -84,6 +84,7 @@ struct serial_struct { struct mac_zschannel { volatile unsigned char *control; volatile unsigned char *data; + spinlock_t lock; }; struct mac_serial { @@ -91,11 +92,13 @@ struct mac_serial { struct mac_zschannel *zs_channel; /* Channel registers */ struct mac_zschannel *zs_chan_a; /* A side registers */ unsigned char read_reg_zero; + struct device_node* dev_node; char soft_carrier; /* Use soft carrier on this channel */ char break_abort; /* Is serial console in, so process brk/abrt */ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ + char is_cobalt_modem; /* is a gatwick-based cobalt modem */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 53f7ab62e..13ce064f4 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -8,6 +8,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#define __KERNEL_SYSCALLS__ + #include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> @@ -16,44 +18,54 @@ #include <linux/sched.h> #include <linux/timer.h> #include <linux/hdreg.h> +#include <linux/stddef.h> +#include <linux/unistd.h> #include <asm/prom.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/ohare.h> +#include <asm/feature.h> #include <asm/mediabay.h> #include <asm/init.h> + +#undef MB_USE_INTERRUPTS + struct media_bay_hw { unsigned char b0; unsigned char contents; unsigned char b2; unsigned char b3; - unsigned feature; }; -static volatile struct media_bay_hw *mb_addr; +struct media_bay_info { + volatile struct media_bay_hw* addr; + int content_id; + int previous_id; + int ready; + int last_value; + int value_count; + int reset_timer; + struct device_node* dev_node; +#ifdef CONFIG_BLK_DEV_IDE + unsigned long cd_base; + int cd_index; + int cd_irq; + int cd_timer; +#endif +}; -#define MB_CONTENTS() ((in_8(&mb_addr->contents) >> 4) & 7) -#define SET_FEATURES(set, clr) \ - out_le32(&mb_addr->feature, \ - (in_le32(&mb_addr->feature) & ~(clr)) | (set)); +#define MAX_BAYS 2 -static int media_bay_id = -1; -static int mb_ready; -static int mb_last_value; -static int mb_value_count; +static volatile struct media_bay_info media_bays[MAX_BAYS]; +int media_bay_count = 0; -int media_bay_present; +#define MB_CONTENTS(i) ((in_8(&media_bays[i].addr->contents) >> 4) & 7) #ifdef CONFIG_BLK_DEV_IDE -unsigned long mb_cd_base; -int mb_cd_index = -1; -int mb_cd_irq; - /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -#define MB_IDE_READY() ((in_8((volatile unsigned char *) \ - (mb_cd_base + 0x70)) & 0x80) == 0) +#define MB_IDE_READY(i) ((in_8((volatile unsigned char *) \ + (media_bays[i].cd_base + 0x70)) & 0x80) == 0) #endif /* @@ -66,16 +78,17 @@ int mb_cd_irq; * Hold the media-bay reset signal true for this many ticks * after a device is inserted before releasing it. */ -#define MB_RESET_COUNT 10 +#define MB_RESET_COUNT 20 /* * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted * (or until the device is ready) before registering the IDE interface. */ -#define MB_IDE_WAIT 500 +#define MB_IDE_WAIT 1000 -static void poll_media_bay(void); -static void set_media_bay(int id); +static void poll_media_bay(int which); +static void set_media_bay(int which, int id); +static int media_bay_task(void *); /* * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL @@ -92,29 +105,62 @@ void media_bay_init(void) { struct device_node *np; - + int n,i; + + for (i=0; i<MAX_BAYS; i++) + { + memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); + media_bays[i].content_id = -1; +#ifdef CONFIG_BLK_DEV_IDE + media_bays[i].cd_index = -1; +#endif + } + np = find_devices("media-bay"); - if (np == NULL || np->n_addrs == 0) - return; - mb_addr = (volatile struct media_bay_hw *) - ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + n = 0; + while(np && (n<MAX_BAYS)) + { + if (np->n_addrs == 0) + continue; + media_bays[n].addr = (volatile struct media_bay_hw *) + ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); -#if 0 - if (np->n_intrs == 0) { - printk(KERN_WARNING "No interrupt for media bay?\n"); - } else { - if (request_irq(np->intrs[0].line, media_bay_intr, 0, - "Media bay", NULL)) - printk(KERN_WARNING "Couldn't get IRQ %d for " - "media bay\n", np->intrs[0].line); - } +#ifdef MB_USE_INTERRUPTS + if (np->n_intrs == 0) + { + printk(KERN_ERR "media bay %d has no irq\n",n); + continue; + } + + if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL)) + { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n); + continue; + } +#endif + media_bay_count++; + + set_media_bay(n, MB_CONTENTS(n)); + if (media_bays[n].content_id != MB_NO) { + feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset); + udelay(500); + } + media_bays[n].ready = 1; + media_bays[n].previous_id = media_bays[n].content_id; + media_bays[n].reset_timer = 0; + media_bays[n].dev_node = np; +#ifdef CONFIG_BLK_DEV_IDE + media_bays[n].cd_timer = 0; #endif + n++; + np=np->next; + } + + if (media_bay_count) + { + printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); - media_bay_present = 1; - set_media_bay(MB_CONTENTS()); - if (media_bay_id != MB_NO) { - SET_FEATURES(0, OH_BAY_RESET); - mb_ready = 1; + kernel_thread(media_bay_task, NULL, 0); } } @@ -130,9 +176,61 @@ media_bay_intr(int irq, void *devid, struct pt_regs *regs) #endif int -check_media_bay(int what) +check_media_bay(struct device_node *which_bay, int what) +{ +#ifdef CONFIG_BLK_DEV_IDE + int i; + + for (i=0; i<media_bay_count; i++) + if (which_bay == media_bays[i].dev_node) + { + if ((what == media_bays[i].content_id) && media_bays[i].ready) + return 0; + media_bays[i].cd_index = -1; + return -EINVAL; + } +#endif /* CONFIG_BLK_DEV_IDE */ + return -ENODEV; +} + +int +check_media_bay_by_base(unsigned long base, int what) +{ + int i; + +#ifdef CONFIG_BLK_DEV_IDE + for (i=0; i<media_bay_count; i++) + if (base == media_bays[i].cd_base) + { + if ((what == media_bays[i].content_id) && media_bays[i].ready) + return 0; + media_bays[i].cd_index = -1; + return -EINVAL; + } +#endif + + return -ENODEV; +} + +int +media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, + int irq, int index) { - return what == media_bay_id && mb_ready; + int i; + +#ifdef CONFIG_BLK_DEV_IDE + for (i=0; i<media_bay_count; i++) + if (which_bay == media_bays[i].dev_node) + { + media_bays[i].cd_base = base; + media_bays[i].cd_irq = irq; + media_bays[i].cd_index = index; + printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i); + return 0; + } +#endif + + return -ENODEV; } /* @@ -144,96 +242,112 @@ check_media_bay(int what) int media_bay_task(void *x) { - int prev = media_bay_id; - int reset_timer = 0; -#ifdef CONFIG_BLK_DEV_IDE - int cd_timer = 0; -#endif - + volatile struct media_bay_info* bay; + int i = 0; + strcpy(current->comm, "media-bay"); - for (;;) { - poll_media_bay(); - if (media_bay_id != prev) { - reset_timer = (media_bay_id != MB_NO)? + for (;;) + { + bay = &media_bays[i]; + poll_media_bay(i); + if (bay->content_id != bay->previous_id) { + bay->reset_timer = (bay->content_id != MB_NO) ? MB_RESET_COUNT: 0; - mb_ready = 0; + bay->ready = 0; #ifdef CONFIG_BLK_DEV_IDE - cd_timer = 0; - if (media_bay_id != MB_CD && mb_cd_index >= 0) { - printk(KERN_DEBUG "Unregistering mb ide\n"); - ide_unregister(mb_cd_index); - mb_cd_index = -1; + bay->cd_timer = 0; + if (bay->content_id != MB_CD && bay->cd_index >= 0) { + printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); + ide_unregister(bay->cd_index); + bay->cd_index = -1; } #endif - } else if (reset_timer) { - if (--reset_timer == 0) { - SET_FEATURES(0, OH_BAY_RESET); - mb_ready = 1; + } else if (bay->reset_timer) { + if (--bay->reset_timer == 0) { + feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->ready = 1; #ifdef CONFIG_BLK_DEV_IDE - if (media_bay_id == MB_CD && mb_cd_base != 0) - cd_timer = MB_IDE_WAIT; + bay->cd_timer = 0; + if (bay->content_id == MB_CD && bay->cd_base != 0) + bay->cd_timer = MB_IDE_WAIT; #endif } #ifdef CONFIG_BLK_DEV_IDE - } else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY()) - && mb_cd_index < 0) { - mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq); - printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index); + } else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i)) + && bay->cd_index < 0) { + bay->cd_timer = 0; + printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq); + printk("\n"); + bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + if (bay->cd_index == -1) + printk("\nCD-ROM badly inserted. Remove it and try again !\n"); + else + printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); #endif } - prev = media_bay_id; + bay->previous_id = bay->content_id; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); if (signal_pending(current)) return 0; + i = (i+1)%media_bay_count; } } void -poll_media_bay(void) +poll_media_bay(int which) { - int id = MB_CONTENTS(); + int id = MB_CONTENTS(which); - if (id == mb_last_value) { - if (id != media_bay_id - && ++mb_value_count >= MB_STABLE_COUNT) - set_media_bay(id); + if (id == media_bays[which].last_value) { + if (id != media_bays[which].content_id + && ++media_bays[which].value_count >= MB_STABLE_COUNT) + set_media_bay(which, id); } else { - mb_last_value = id; - mb_value_count = 0; + media_bays[which].last_value = id; + media_bays[which].value_count = 0; } } static void -set_media_bay(int id) +set_media_bay(int which, int id) { - u32 clr, set; + volatile struct media_bay_info* bay; - media_bay_id = id; - mb_last_value = id; - clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER; - set = 0; + bay = &media_bays[which]; + + bay->content_id = id; + bay->last_value = id; + switch (id) { case MB_CD: - set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE; - printk(KERN_INFO "media bay contains a CD-ROM drive\n"); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + feature_set(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable); + printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); break; case MB_FD: - set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE; - printk(KERN_INFO "media bay contains a floppy disk drive\n"); + feature_clear(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_SWIM3_enable); + printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); break; case MB_NO: - printk(KERN_INFO "media bay is empty\n"); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(bay->dev_node, FEATURE_CD_power); + printk(KERN_INFO "media bay %d is empty\n", which); break; default: - set = OH_BAY_ENABLE; - printk(KERN_INFO "media bay contains an unknown device (%d)\n", - id); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(bay->dev_node, FEATURE_CD_power); + feature_set(bay->dev_node, FEATURE_Mediabay_enable); + printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", + which, id); break; } - - SET_FEATURES(set, clr); - printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature)); + + udelay(500); } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 986cdd7b5..b0b7dd7d2 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -80,7 +80,8 @@ static void cuda_start(void); static void via_interrupt(int irq, void *arg, struct pt_regs *regs); static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); static int cuda_adb_send_request(struct adb_request *req, int sync); -static int cuda_adb_autopoll(int on); +static int cuda_adb_autopoll(int devs); +static int cuda_reset_bus(void); __openfirmware @@ -141,6 +142,7 @@ via_cuda_init(void) /* Set function pointers */ adb_send_request = cuda_adb_send_request; adb_autopoll = cuda_adb_autopoll; + adb_reset_bus = cuda_reset_bus; } #define WAIT_FOR(cond, what) \ @@ -216,11 +218,23 @@ cuda_adb_send_request(struct adb_request *req, int sync) /* Enable/disable autopolling */ static int -cuda_adb_autopoll(int on) +cuda_adb_autopoll(int devs) { struct adb_request req; - cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, on); + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0)); + while (!req.complete) + cuda_poll(); + return 0; +} + +/* Reset adb bus - how do we do this?? */ +static int +cuda_reset_bus(void) +{ + struct adb_request req; + + cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */ while (!req.complete) cuda_poll(); return 0; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 407a93002..4dd82fef9 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -30,6 +30,7 @@ #include <asm/system.h> #include <asm/init.h> #include <asm/irq.h> +#include <asm/feature.h> /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -99,7 +100,8 @@ static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); static int pmu_adb_send_request(struct adb_request *req, int sync); -static int pmu_adb_autopoll(int on); +static int pmu_adb_autopoll(int devs); +static int pmu_reset_bus(void); static void send_byte(int x); static void recv_byte(void); static void pmu_sr_intr(struct pt_regs *regs); @@ -162,6 +164,8 @@ find_via_pmu() return; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); + + feature_set(vias, FEATURE_VIA_enable); #if 0 { int i; @@ -215,6 +219,7 @@ via_pmu_init(void) /* Set function pointers */ adb_send_request = pmu_adb_send_request; adb_autopoll = pmu_adb_autopoll; + adb_reset_bus = pmu_reset_bus; } static int @@ -281,11 +286,12 @@ pmu_adb_send_request(struct adb_request *req, int sync) /* Enable/disable autopolling */ static int -pmu_adb_autopoll(int on) +pmu_adb_autopoll(int devs) { struct adb_request req; - if (on) { + if (devs) { + adb_dev_map = devs; pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, adb_dev_map >> 8, adb_dev_map); pmu_adb_flags = 2; @@ -298,6 +304,49 @@ pmu_adb_autopoll(int on) return 0; } +/* Reset the ADB bus */ +static int +pmu_reset_bus(void) +{ + struct adb_request req; + long timeout; + int save_autopoll = adb_dev_map; + + /* anyone got a better idea?? */ + pmu_adb_autopoll(0); + + req.nbytes = 5; + req.done = NULL; + req.data[0] = PMU_ADB_CMD; + req.data[1] = 0; + req.data[2] = 3; + req.data[3] = 0; + req.data[4] = 0; + req.reply_len = 0; + req.reply_expected = 1; + if (pmu_queue_request(&req) != 0) + { + printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n"); + return 0; + } + while (!req.complete) + pmu_poll(); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n"); + return 0; + } + udelay(10); + pmu_poll(); + } + + if (save_autopoll != 0) + pmu_adb_autopoll(save_autopoll); + + return 1; +} + /* Construct and send a pmu request */ int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), @@ -366,7 +415,10 @@ pmu_send_request(struct adb_request *req) req->nbytes = 5; for (i = 1; i <= 4; ++i) req->data[i] = req->data[i+1]; - req->reply_len = 0; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_SET_TIME; return pmu_queue_request(req); } break; @@ -691,6 +743,44 @@ set_volume(int level) { } +void +pmu_restart(void) +{ + struct adb_request req; + + _disable_interrupts(); + + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT); + while(!req.complete) + pmu_poll(); + + pmu_request(&req, NULL, 1, PMU_RESET); + while(!req.complete || (pmu_state != idle)) + pmu_poll(); + for (;;) + ; +} + +void +pmu_shutdown(void) +{ + struct adb_request req; + + _disable_interrupts(); + + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, CB1_INT); + while(!req.complete) + pmu_poll(); + + pmu_request(&req, NULL, 5, PMU_SHUTDOWN, + 'M', 'A', 'T', 'T'); + while(!req.complete || (pmu_state != idle)) + pmu_poll(); + for (;;) + ; +} + + #ifdef CONFIG_PMAC_PBOOK /* @@ -855,12 +945,14 @@ int powerbook_sleep(void) notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); /* reenable ADB autopoll */ - pmu_adb_autopoll(1); + pmu_adb_autopoll(adb_dev_map); /* Turn on the screen backlight, if it was on before */ if (save_backlight) pmu_enable_backlight(1); + /* Wait for the hard disk to spin up */ + return 0; } |