mediabay.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 857 行 · 第 1/2 页
C
857 行
/* * 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. */#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/init.h>#include <linux/ide.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>#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#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; void (*init)(struct media_bay_info *bay); 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 macio_dev *mdev; struct mb_ops* ops; int index; int cached_gpio; int sleeping; struct semaphore lock;#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) ((readb(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 + 999) / 1000)/* * Wait that number of ms between each step in normal polling mode */#define MB_POLL_DELAY 25/* * 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 50/* * 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 __pmac keylargo_mb_init(struct media_bay_info *bay){ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE);}static void __pmac heathrow_mb_un_reset(struct media_bay_info* bay){ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);}static void __pmac keylargo_mb_un_reset(struct media_bay_info* bay){ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);}static void __pmac ohare_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);}static void __pmac heathrow_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);}static void __pmac keylargo_mb_un_reset_ide(struct media_bay_info* bay){ MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);}static inline void __pmac set_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 __pmac poll_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_POLL_DELAY); if (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; if (id == MB_NO) {#ifdef CONFIG_BLK_DEV_IDE bay->cd_retry = 0;#endif printk(KERN_INFO "media bay %d is empty\n", bay->index); } } } } else { bay->last_value = id; bay->value_count = 0; }}int __pmac 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 (media_bays[i].mdev && which_bay == media_bays[i].mdev->ofdev.node) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?