📄 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/machdep.h>#include <asm/pmac_feature.h>#include <asm/mediabay.h>#include <asm/sections.h>#include <asm/ohare.h>#include <asm/heathrow.h>#include <asm/keylargo.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#define 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)#endif/* Type of media bay */enum { mb_ohare, mb_heathrow, mb_keylargo};#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2))#define MB_FCR8(bay, r) (((volatile u8*)((bay)->base)) + (r))#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r)))#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v)))#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v)))#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v)))#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r)))#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v)))struct media_bay_info;struct mb_ops { char* name; u8 (*content)(struct media_bay_info* bay); void (*power)(struct media_bay_info* bay, int on_off); int (*setup_bus)(struct media_bay_info* bay, u8 device_id); void (*un_reset)(struct media_bay_info* bay); void (*un_reset_ide)(struct media_bay_info* bay);};struct media_bay_info { volatile u32* base; int content_id; int state; int last_value; int value_count; int timer; struct device_node* dev_node; int mb_type; struct mb_ops* ops; int index; int cached_gpio;#ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; int cd_irq; int cd_retry;#endif};#define MAX_BAYS 2static struct media_bay_info media_bays[MAX_BAYS];int media_bay_count = 0;#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) & 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 100/* 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) */};#define MB_POWER_SOUND 0x08#define MB_POWER_FLOPPY 0x04#define MB_POWER_ATA 0x02#define MB_POWER_PCI 0x01#define MB_POWER_OFF 0x00/* * Functions for polling content of media bay */ static u8 __pmacohare_mb_content(struct media_bay_info *bay){ return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7;}static u8 __pmacheathrow_mb_content(struct media_bay_info *bay){ return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7;}static u8 __pmackeylargo_mb_content(struct media_bay_info *bay){ int new_gpio; new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; if (new_gpio) { bay->cached_gpio = new_gpio; return MB_NO; } else if (bay->cached_gpio != new_gpio) { MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); (void)MB_IN32(bay, KEYLARGO_MBCR); udelay(5); MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); (void)MB_IN32(bay, KEYLARGO_MBCR); udelay(5); bay->cached_gpio = new_gpio; } return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7;}/* * Functions for powering up/down the bay, puts the bay device * into reset state as well */static void __pmacohare_mb_power(struct media_bay_info* bay, int on_off){ if (on_off) { /* Power up device, assert it's reset line */ MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N); MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N); } else { /* Disable all devices */ MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK); MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE); /* Cut power from bay, release reset line */ MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N); MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); } MB_BIC(bay, OHARE_MBCR, 0x00000F00);}static void __pmacheathrow_mb_power(struct media_bay_info* bay, int on_off){ if (on_off) { /* Power up device, assert it's reset line */ MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); } else { /* Disable all devices */ MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); /* Cut power from bay, release reset line */ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); } MB_BIC(bay, HEATHROW_MBCR, 0x00000F00);}static void __pmackeylargo_mb_power(struct media_bay_info* bay, int on_off){ if (on_off) { /* Power up device, assert it's reset line */ MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); } else { /* Disable all devices */ MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); /* Cut power from bay, release reset line */ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); } MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F);}/* * Functions for configuring the media bay for a given type of device, * enable the related busses */static int __pmacohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id){ switch(device_id) { case MB_FD: case MB_FD1: MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); return 0; case MB_CD: MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); return 0; case MB_PCI: MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); return 0; } return -ENODEV;}static int __pmacheathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id){ switch(device_id) { case MB_FD: case MB_FD1: MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); return 0; case MB_CD: MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); return 0; case MB_PCI: MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); return 0; } return -ENODEV;}static int __pmackeylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id){ switch(device_id) { case MB_CD: MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); return 0; case MB_PCI: MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); return 0; case MB_SOUND: MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); return 0; } return -ENODEV;}/* * Functions for tweaking resets */static void __pmacohare_mb_un_reset(struct media_bay_info* bay){ MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N);}static void __pmacheathrow_mb_un_reset(struct media_bay_info* bay){ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);}static void __pmackeylargo_mb_un_reset(struct media_bay_info* bay){ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);}static void __pmacohare_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);}static void __pmacheathrow_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);}static void __pmackeylargo_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);}static inline void __pmacset_mb_power(struct media_bay_info* bay, int onoff){ /* Power up up and assert the bay reset line */ if (onoff) { bay->ops->power(bay, 1); bay->state = mb_powering_up; MBDBG("mediabay%d: powering up\n", bay->index); } else { /* Make sure everything is powered down & disabled */ bay->ops->power(bay, 0); bay->state = mb_powering_down; MBDBG("mediabay%d: powering down\n", bay->index); } bay->timer = MS_TO_HZ(MB_POWER_DELAY);}static void __pmacpoll_media_bay(struct media_bay_info* bay){ int id = bay->ops->content(bay); if (id == bay->last_value) { if (id != bay->content_id && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { /* If the device type changes without going thru "MB_NO", we force a pass by "MB_NO" to make sure things are properly reset */ if ((id != MB_NO) && (bay->content_id != MB_NO)) { id = MB_NO; MBDBG("mediabay%d: forcing MB_NO\n", bay->index); } MBDBG("mediabay%d: switching to %d\n", bay->index, id); set_mb_power(bay, id != MB_NO); bay->content_id = id;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -