📄 mediabay.c
字号:
/* * Driver for the media bay on the PowerBook 3400 and 2400. * * Copyright (C) 1998 Paul Mackerras. * * Various evolutions by Benjamin Herrenschmidt & Henry Worth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * 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>#include <linux/kernel.h>#include <linux/delay.h>#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/feature.h>#include <asm/mediabay.h>#include <asm/init.h>#include <linux/adb.h>#include <linux/pmu.h>#ifdef CONFIG_PMAC_PBOOKstatic int mb_notify_sleep(struct pmu_sleep_notifier *self, int when);static struct pmu_sleep_notifier mb_sleep_notifier = { mb_notify_sleep, SLEEP_LEVEL_MEDIABAY,};#endif#undef MB_USE_INTERRUPTS#undef MB_DEBUG#define MB_IGNORE_SIGNALS#ifdef MB_DEBUG#define MBDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)#else#define MBDBG(fmt, arg...) do { } while (0)#endifstruct media_bay_hw { unsigned char b0; unsigned char contents; unsigned char b2; unsigned char b3;};struct media_bay_info { volatile struct media_bay_hw* addr; volatile u8* extint_gpio; int content_id; int state; int last_value; int value_count; int timer; struct device_node* dev_node; int pismo; /* New PowerBook3,1 */ int gpio_cache;#ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; int cd_irq; int cd_retry;#endif};#define MAX_BAYS 2static volatile struct media_bay_info media_bays[MAX_BAYS];int media_bay_count = 0;inline int mb_content(volatile struct media_bay_info *bay){ if (bay->pismo) { unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2; if (new_gpio) { bay->gpio_cache = new_gpio; return MB_NO; } else if (bay->gpio_cache != new_gpio) { /* make sure content bits are set */ feature_set(bay->dev_node, FEATURE_Mediabay_content); udelay(5); bay->gpio_cache = new_gpio; } return (in_le32((unsigned*)bay->addr) >> 4) & 0xf; } else { int cont = (in_8(&bay->addr->contents) >> 4) & 7; return (cont == 7) ? MB_NO : cont; }}#ifdef CONFIG_BLK_DEV_IDE/* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) *///#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40)#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0)#endif/* Note: All delays are not in milliseconds and converted to HZ relative * values by the macro below */#define MS_TO_HZ(ms) ((ms * HZ) / 1000)/* * Consider the media-bay ID value stable if it is the same for * this number of milliseconds */#define MB_STABLE_DELAY 40/* Wait after powering up the media bay this delay in ms * timeout bumped for some powerbooks */#define MB_POWER_DELAY 200/* * Hold the media-bay reset signal true for this many ticks * after a device is inserted before releasing it. */#define MB_RESET_DELAY 40/* * Wait this long after the reset signal is released and before doing * further operations. After this delay, the IDE reset signal is released * too for an IDE device */#define MB_SETUP_DELAY 100/* * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted * (or until the device is ready) before waiting for busy bit to disappear */#define MB_IDE_WAIT 1000/* * Timeout waiting for busy bit of an IDE device to go down */#define MB_IDE_TIMEOUT 5000/* * Max retries of the full power up/down sequence for an IDE device */#define MAX_CD_RETRIES 3/* * States of a media bay */enum { mb_empty = 0, /* Idle */ mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */ mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */ mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */ mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */ mb_ide_waiting, /* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */ mb_up, /* Media bay full */ mb_powering_down /* Powering down (avoid too fast down/up) */};static void poll_media_bay(int which);static void set_media_bay(int which, int id);static void set_mb_power(int which, int onoff);static void media_bay_step(int i);static int media_bay_task(void *);#ifdef MB_USE_INTERRUPTSstatic void media_bay_intr(int irq, void *devid, struct pt_regs *regs);#endif/* * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL * register is always set when there is something in the media bay. * This causes problems for the interrupt code if we attach an interrupt * handler to the media-bay interrupt, because it tends to go into * an infinite loop calling the media bay interrupt handler. * Therefore we do it all by polling the media bay once each tick. */void __pmacmedia_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"); 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)); media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay"); if (media_bays[n].pismo) { if (!np->parent || strcmp(np->parent->name, "mac-io")) { printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n"); continue; } media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address + 0x58, 0x10); }#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", (void *)n)) { printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", np->intrs[0].line, n); continue; }#endif media_bay_count++; media_bays[n].dev_node = np; /* Force an immediate detect */ set_mb_power(n,0); mdelay(MB_POWER_DELAY); if(!media_bays[n].pismo) out_8(&media_bays[n].addr->contents, 0x70); mdelay(MB_STABLE_DELAY); media_bays[n].content_id = MB_NO; media_bays[n].last_value = mb_content(&media_bays[n]); media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY); media_bays[n].state = mb_empty; do { mdelay(1000/HZ); media_bay_step(n); } while((media_bays[n].state != mb_empty) && (media_bays[n].state != mb_up)); n++; np=np->next; } if (media_bay_count) { printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);#ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&mb_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */ kernel_thread(media_bay_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); }}#ifdef MB_USE_INTERRUPTSstatic void __pmacmedia_bay_intr(int irq, void *devid, struct pt_regs *regs){}#endifstatic void __pmacset_mb_power(int which, int onoff){ volatile struct media_bay_info* mb = &media_bays[which]; if (onoff) { feature_set(mb->dev_node, FEATURE_Mediabay_power); udelay(10); feature_set(mb->dev_node, FEATURE_Mediabay_reset); udelay(10); mb->state = mb_powering_up; MBDBG("mediabay%d: powering up\n", which); } else { feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable); if (mb->pismo) feature_clear(mb->dev_node, FEATURE_IDE0_enable); else feature_clear(mb->dev_node, FEATURE_IDE1_enable); feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch); feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable); feature_clear(mb->dev_node, FEATURE_SWIM3_enable); feature_clear(mb->dev_node, FEATURE_Mediabay_power); mb->state = mb_powering_down; MBDBG("mediabay%d: powering down\n", which); } mb->timer = MS_TO_HZ(MB_POWER_DELAY);}static void __pmacset_media_bay(int which, int id){ volatile struct media_bay_info* bay; bay = &media_bays[which]; switch (id) { case MB_CD: if (bay->pismo) { feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch); udelay(10); feature_set(bay->dev_node, FEATURE_IDE0_enable); udelay(10); feature_set(bay->dev_node, FEATURE_IDE0_reset); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -