diff options
author | Cliff Brake <cbrake@bec-systems.com> | 2007-01-31 13:41:09 +0000 |
---|---|---|
committer | Cliff Brake <cbrake@bec-systems.com> | 2007-01-31 13:41:09 +0000 |
commit | a3990a712303e30e9d131f4c146f1cfde44255ed (patch) | |
tree | ced2d3edc8c7fe37b3d9f9840dddbff71fcc54e2 /packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch | |
parent | 7a2c81bf198b4bcd8f344a1ef72734d1d605bba9 (diff) |
logicpd-pxa270 2.6.19.2: update kernel, contributed by Shane Volpe
Diffstat (limited to 'packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch')
-rw-r--r-- | packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch b/packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch new file mode 100644 index 0000000000..ec1256261b --- /dev/null +++ b/packages/linux/logicpd-pxa270-2.6.19.2/logicpd-pxa270-cf-hack.patch @@ -0,0 +1,727 @@ +Index: drivers/block/Kconfig +=================================================================== +RCS file: /cvs/eps/dev_eng/sw/products/Linux/PXAEngine/pxa/linux-2.6.17-rc5/drivers/block/Kconfig,v +retrieving revision 1.1.1.1 +retrieving revision 1.2 +diff -c -3 -p -r1.1.1.1 -r1.2 +*** drivers/block/Kconfig 29 May 2006 00:55:20 -0000 1.1.1.1 +--- drivers/block/Kconfig 1 Jun 2006 17:05:41 -0000 1.2 +*************** +*** 4,9 **** +--- 4,16 ---- + + menu "Block devices" + ++ config BLK_DEV_LOGICPD_CF ++ bool "LogicPD memory-mapped CompactFlash card support" ++ depends on MACH_LOGICPD_PXA270 ++ ---help--- ++ If you want to use the memory-mapped comapct flash card on ++ the LogicPD SDK, say Y. ++ + config BLK_DEV_FD + tristate "Normal floppy disk support" + depends on ARCH_MAY_HAVE_PC_FDC +Index: drivers/block/Makefile +=================================================================== +RCS file: /cvs/eps/dev_eng/sw/products/Linux/PXAEngine/pxa/linux-2.6.17-rc5/drivers/block/Makefile,v +retrieving revision 1.1.1.1 +retrieving revision 1.2 +diff -c -3 -p -r1.1.1.1 -r1.2 +*** drivers/block/Makefile 29 May 2006 00:55:20 -0000 1.1.1.1 +--- drivers/block/Makefile 1 Jun 2006 17:05:59 -0000 1.2 +*************** +*** 5,10 **** +--- 5,12 ---- + # Rewritten to use lists instead of if-statements. + # + ++ obj-$(CONFIG_BLK_DEV_LOGICPD_CF)+= lpd270-cf.o ++ + obj-$(CONFIG_MAC_FLOPPY) += swim3.o + obj-$(CONFIG_BLK_DEV_FD) += floppy.o + obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o +Index: drivers/block/lpd270-cf.c +=================================================================== +RCS file: drivers/block/lpd270-cf.c +diff -N drivers/block/lpd270-cf.c +*** /dev/null 1 Jan 1970 00:00:00 -0000 +--- drivers/block/lpd270-cf.c 1 Jun 2006 16:23:35 -0000 1.1 +*************** +*** 0 **** +--- 1,675 ---- ++ /* ++ * Support for LogicPD SDK Memory-mapped CompactFlash interface ++ * ++ * Copyright 2006 Logic Product Development <peterb@logicpd.com> ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++ ++ /* Uncomment the following if you want verbose error reports. */ ++ /* #define VERBOSE_ERRORS */ ++ ++ #include <linux/blkdev.h> ++ #include <linux/errno.h> ++ #include <linux/signal.h> ++ #include <linux/interrupt.h> ++ #include <linux/timer.h> ++ #include <linux/fs.h> ++ #include <linux/kernel.h> ++ #include <linux/genhd.h> ++ #include <linux/slab.h> ++ #include <linux/string.h> ++ #include <linux/ioport.h> ++ #include <linux/mc146818rtc.h> /* CMOS defines */ ++ #include <linux/init.h> ++ #include <linux/blkpg.h> ++ #include <linux/hdreg.h> ++ ++ #define REALLY_SLOW_IO ++ #include <asm/system.h> ++ #include <asm/io.h> ++ #include <asm/uaccess.h> ++ #include <asm/delay.h> ++ ++ #ifdef __arm__ ++ #undef HD_IRQ ++ #endif ++ #include <asm/irq.h> ++ #ifdef __arm__ ++ #define HD_IRQ IRQ_HARDDISK ++ #endif ++ ++ #define DEBUG ++ ++ /* Hd controller regster ports */ ++ ++ #define HD_DATA 0x1f0 /* _CTL when writing */ ++ #define HD_ERROR 0x1f1 /* see err-bits */ ++ #define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ ++ #define HD_SECTOR 0x1f3 /* starting sector */ ++ #define HD_LCYL 0x1f4 /* starting cylinder */ ++ #define HD_HCYL 0x1f5 /* high byte of starting cyl */ ++ #define HD_CURENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ ++ #define HD_STATUS 0x1f7 /* see status-bits */ ++ #define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */ ++ #define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */ ++ #define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ ++ ++ #define HD_CMD 0x3f6 /* used for resets */ ++ #define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */ ++ ++ /* Bits of HD_STATUS */ ++ #define ERR_STAT 0x01 ++ #define INDEX_STAT 0x02 ++ #define ECC_STAT 0x04 /* Corrected error */ ++ #define DRQ_STAT 0x08 ++ #define SEEK_STAT 0x10 ++ #define SERVICE_STAT SEEK_STAT ++ #define WRERR_STAT 0x20 ++ #define READY_STAT 0x40 ++ #define BUSY_STAT 0x80 ++ ++ /* Bits for HD_ERROR */ ++ #define MARK_ERR 0x01 /* Bad address mark */ ++ #define TRK0_ERR 0x02 /* couldn't find track 0 */ ++ #define ABRT_ERR 0x04 /* Command aborted */ ++ #define MCR_ERR 0x08 /* media change request */ ++ #define ID_ERR 0x10 /* ID field not found */ ++ #define MC_ERR 0x20 /* media changed */ ++ #define ECC_ERR 0x40 /* Uncorrectable ECC error */ ++ #define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ ++ #define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ ++ ++ static DEFINE_SPINLOCK(hd_lock); ++ static struct request_queue *hd_queue; ++ ++ #define MAJOR_NR HD_MAJOR ++ #define QUEUE (hd_queue) ++ #define CURRENT elv_next_request(hd_queue) ++ ++ #define TIMEOUT_VALUE (6*HZ) ++ #define HD_DELAY 0 ++ ++ #define MAX_ERRORS 16 /* Max read/write errors/sector */ ++ #define RESET_FREQ 8 /* Reset controller every 8th retry */ ++ #define RECAL_FREQ 4 /* Recalibrate every 4th retry */ ++ #define MAX_HD 2 ++ ++ #define STAT_OK (READY_STAT|SEEK_STAT) ++ #define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK) ++ ++ static int driveno = 0; ++ static int debug = 0; ++ ++ // Start of CF registers ++ #define CPLD_ATA_REG_BASE 0x14001800 ++ static unsigned char *reg_base; ++ ++ static inline unsigned int read_reg(unsigned char *base, unsigned int reg) ++ { ++ volatile unsigned short val; ++ ++ if (reg & 1) ++ val = *((volatile unsigned short *)(base + reg - 1)) >> 8; ++ else ++ val = *((volatile unsigned short *)(base + reg)); ++ ++ if (debug) ++ printk("%s: %02x %04x \n", __FUNCTION__, reg, val); ++ ++ return val; ++ } ++ ++ static inline void write_reg(unsigned char *base, unsigned int reg, unsigned int val) ++ { ++ if (debug) ++ printk("%s: %02x %04x\n", __FUNCTION__, reg, val); ++ if (reg & 1) ++ *((volatile unsigned short *)(base + reg - 1)) = (val << 8); ++ else ++ *((volatile unsigned short *)(base + reg)) = val; ++ } ++ ++ #define CB_DATA 0x08 ++ #define CB_ERR 0x0d ++ #define CB_SC_SN 0x02 ++ #define CB_CYL 0x04 ++ #define CB_STAT 0x07 ++ #define CB_DH_CMD 0x06 ++ #define CB_ASTAT 0x0e ++ #define CB_DC 0x0e ++ #define CB_DA 0x0f ++ ++ #define CB_STAT_BSY 0x80 ++ #define CB_STAT_DRQ 0x08 ++ #define CB_STAT_SEEK 0x10 ++ #define CB_STAT_DF 0x20 ++ #define CB_STAT_READY 0x40 ++ #define CB_STAT_ERR 0x01 ++ #define CB_DC_HD15 0x08 ++ #define CB_DC_NIEN 0x02 ++ ++ #define CMD_IDENTIFY_DEVICE 0xec ++ #define CMD_READ_SECTORS 0x20 ++ #define CMD_WRITE_SECTORS 0x30 ++ ++ #define TIMEOUT 0x800000 ++ ++ int cfide_card_present(void) ++ { ++ unsigned char data, data1, data2; ++ ++ /* Flip Sector Count */ ++ data = read_reg(reg_base, CB_SC_SN); ++ data1 = (~data) & 0xff; ++ write_reg(reg_base, CB_SC_SN, data1); ++ ++ /* write to the data register to waggle the bus */ ++ write_reg(reg_base, CB_DATA, data); ++ ++ /* Read back the sector count and if it matches what we put there ++ then the CF is present */ ++ data2 = read_reg(reg_base, CB_SC_SN); ++ if (data2 == data1) ++ return 1; ++ else { ++ printk("data %02x data1 %02x data2 %02x\n", data, data1, data2); ++ return 0; ++ } ++ } ++ ++ /* ++ * This struct defines the HD's and their types. ++ */ ++ struct hd_i_struct { ++ unsigned int head,sect,cyl,wpcom,lzone,ctl; ++ int unit; ++ int recalibrate; ++ int special_op; ++ }; ++ ++ #ifdef HD_TYPE ++ static struct hd_i_struct hd_info[] = { HD_TYPE }; ++ static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct))); ++ #else ++ static struct hd_i_struct hd_info[MAX_HD]; ++ static int NR_HD; ++ #endif ++ ++ static struct gendisk *hd_gendisk[MAX_HD]; ++ ++ ++ ++ #if (HD_DELAY > 0) ++ ++ #include <asm/i8253.h> ++ ++ unsigned long last_req; ++ ++ unsigned long read_timer(void) ++ { ++ unsigned long t, flags; ++ int i; ++ ++ spin_lock_irqsave(&i8253_lock, flags); ++ t = jiffies * 11932; ++ outb_p(0, 0x43); ++ i = inb_p(0x40); ++ i |= inb(0x40) << 8; ++ spin_unlock_irqrestore(&i8253_lock, flags); ++ return(t - i); ++ } ++ #endif ++ ++ static void __init hd_setup(char *str, int *ints) ++ { ++ int hdind = 0; ++ ++ if (ints[0] != 3) ++ return; ++ if (hd_info[0].head != 0) ++ hdind=1; ++ hd_info[hdind].head = ints[2]; ++ hd_info[hdind].sect = ints[3]; ++ hd_info[hdind].cyl = ints[1]; ++ hd_info[hdind].wpcom = 0; ++ hd_info[hdind].lzone = ints[1]; ++ hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0); ++ NR_HD = hdind+1; ++ } ++ ++ ++ ++ void cfide_wait_fin(void) ++ { ++ unsigned long timer; ++ ++ // printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ udelay(500); // wait 500us ++ ++ for (timer = 0; ++ timer < TIMEOUT && (read_reg(reg_base, CB_STAT) & CB_STAT_BSY); ++timer) ++ yield(); ++ ++ if (timer == TIMEOUT) ++ printk("%s:%d\n", __FUNCTION__, __LINE__); ++ } ++ ++ void cfide_wait_drq(void) ++ { ++ unsigned long timer; ++ ++ for (timer = 0; ++ timer < TIMEOUT && !(read_reg(reg_base, CB_STAT) & CB_STAT_DRQ); ++timer) ++ yield(); ++ ++ if (timer == TIMEOUT) ++ printk("%s:%d\n", __FUNCTION__, __LINE__); ++ } ++ ++ static union { ++ struct hd_driveid id; ++ short sh[512/2]; ++ } info_buf; ++ ++ ++ /* Read cnt sectors from the flash, starting at lba, storing the data ++ at dest */ ++ static int cfide_read_sectors(uint8_t *dest, uint32_t lba, uint32_t cnt) ++ { ++ uint8_t sect, head, devHead, status, devCtrl; ++ uint16_t cyl; ++ uint32_t orig_lba = lba; ++ uint32_t i,j; ++ uint16_t data; ++ ++ // printk("%s: dest %p lba %u cnt %u\n", __FUNCTION__, dest, lba, cnt); ++ ++ if (lba + cnt > info_buf.id.lba_capacity) { ++ printk("%s: %u+%u is larger than %u\n", __FUNCTION__, lba, cnt, info_buf.id.lba_capacity); ++ return -EINVAL; ++ } ++ ++ if (cnt > 255) { ++ printk("%s: cnt %u is too large\n", __FUNCTION__, cnt); ++ return -EINVAL; ++ } ++ ++ ++ /* translate from LBA */ ++ sect = lba & 0xff; ++ lba >>= 8; ++ cyl = lba & 0xffff; ++ lba >>= 16; ++ head = (lba & 0x0f) | 0x40; ++ ++ devCtrl = CB_DC_HD15 | CB_DC_NIEN; ++ devHead = driveno | head; ++ ++ write_reg(reg_base, CB_DC, devCtrl); ++ write_reg(reg_base, CB_SC_SN, ((uint16_t)cnt & 0xff) | ((uint16_t)sect << 8)); ++ write_reg(reg_base, CB_CYL, cyl); ++ ++ write_reg(reg_base, CB_DH_CMD, devHead | (CMD_READ_SECTORS << 8)); ++ ++ for (j=0; j<cnt; ++j) { ++ udelay(1); // spin for a moment to let the controller raise BSY ++ ++ cfide_wait_fin(); ++ cfide_wait_drq(); ++ for (i=0; i<256; ++i) { ++ data = read_reg(reg_base, CB_DATA); ++ #if 0 ++ *dest++ = data>>8; ++ *dest++ = data; ++ #else ++ *dest++ = data; ++ *dest++ = data>>8; ++ #endif ++ } ++ ++ ++ cfide_wait_fin(); ++ ++ status = read_reg(reg_base, CB_STAT); ++ if (status & (CB_STAT_DF|CB_STAT_ERR)) { ++ printk("%s: error at block %d status %#x\n", __FUNCTION__, orig_lba+j, status); ++ break; ++ } ++ ++ } ++ ++ return 0; ++ } ++ ++ /* Write cnt sectors to the flash, starting at lba, reading the data ++ from src */ ++ static int cfide_write_sectors(uint8_t *src, uint32_t lba, uint32_t cnt) ++ { ++ uint8_t sect, head, devHead, status, devCtrl; ++ uint16_t cyl; ++ uint32_t orig_lba = lba; ++ uint32_t i,j; ++ uint16_t data; ++ ++ if (lba + cnt > info_buf.id.lba_capacity) { ++ printk("%s: %u+%u is larger than %u\n", __FUNCTION__, lba, cnt, info_buf.id.lba_capacity); ++ return -EINVAL; ++ } ++ ++ if (cnt > 255) { ++ printk("%s: cnt %u is too large\n", __FUNCTION__, cnt); ++ return -EINVAL; ++ } ++ ++ /* translate from LBA */ ++ sect = lba & 0xff; ++ lba >>= 8; ++ cyl = lba & 0xffff; ++ lba >>= 16; ++ head = (lba & 0x0f) | 0x40; ++ ++ devCtrl = CB_DC_HD15 | CB_DC_NIEN; ++ devHead = driveno | head; ++ ++ write_reg(reg_base, CB_DC, devCtrl); ++ write_reg(reg_base, CB_SC_SN, ((uint16_t)cnt & 0xff) | ((uint16_t)sect << 8)); ++ write_reg(reg_base, CB_CYL, cyl); ++ ++ write_reg(reg_base, CB_DH_CMD, devHead | (CMD_WRITE_SECTORS << 8)); ++ ++ for (j=0; j<cnt; ++j) { ++ udelay(1); // spin for a moment to let the controller raise BSY ++ ++ cfide_wait_fin(); ++ ++ cfide_wait_drq(); ++ ++ for (i=0; i<256; ++i) { ++ #if 0 ++ data = (*src++ << 8); ++ data |= *src++; ++ #else ++ data = *src++; ++ data |= (*src++ << 8); ++ #endif ++ write_reg(reg_base, CB_DATA, data); ++ } ++ ++ cfide_wait_fin(); ++ ++ status = read_reg(reg_base, CB_STAT); ++ if (status & (CB_STAT_DF|CB_STAT_ERR)) { ++ printk("%s: error at block %d status %#x\n", __FUNCTION__, orig_lba+j, status); ++ break; ++ } ++ ++ } ++ return 0; ++ } ++ ++ ++ static void cfide_transfer(unsigned long sector, ++ unsigned long nsect, char *buffer, int write) ++ { ++ int ret; ++ if (write) ++ ret = cfide_write_sectors(buffer, sector, nsect); ++ else ++ ret = cfide_read_sectors(buffer, sector, nsect); ++ if (ret) ++ printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ } ++ ++ ++ static void do_hd_request (request_queue_t * q) ++ { ++ struct request *req; ++ ++ // printk("%s:%d q %p\n", __FUNCTION__, __LINE__, q); ++ ++ while ((req = elv_next_request(q)) != NULL) { ++ if (blk_fs_request(req)) { ++ cfide_transfer(req->sector, req->current_nr_sectors, ++ req->buffer, rq_data_dir(req)); ++ end_request(req, 1); ++ } else { ++ printk (KERN_NOTICE "Skip non-fs request\n"); ++ end_request(req, 0); ++ continue; ++ } ++ } ++ } ++ ++ static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) ++ { ++ struct hd_i_struct *disk = bdev->bd_disk->private_data; ++ ++ geo->heads = disk->head; ++ geo->sectors = disk->sect; ++ geo->cylinders = disk->cyl; ++ return 0; ++ } ++ ++ ++ static struct block_device_operations hd_fops = { ++ .getgeo = hd_getgeo, ++ }; ++ ++ void cfide_fetch_info(void) ++ { ++ int i; ++ ++ // printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ /* Select the drive and wait for it to finish */ ++ driveno &= 1; ++ write_reg(reg_base, CB_DH_CMD, driveno); ++ cfide_wait_fin(); ++ ++ // printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ write_reg(reg_base, CB_DH_CMD, driveno | (CMD_IDENTIFY_DEVICE << 8)); ++ cfide_wait_fin(); ++ ++ // printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ ++ cfide_wait_drq(); ++ ++ // printk("%s:%d\n", __FUNCTION__, __LINE__); ++ ++ for (i=0; i<512; i+=2) ++ info_buf.sh[i/2] = read_reg(reg_base, CB_DATA); ++ ++ /* Fix lba_capcity */ ++ info_buf.id.lba_capacity = (info_buf.id.lba_capacity>>16) | (info_buf.id.lba_capacity<<16); ++ // printk("%s:%d lba_capacity %#x\n", __FUNCTION__, __LINE__, info_buf.id.lba_capacity); ++ } ++ ++ /* ++ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags ++ * means we run the IRQ-handler with interrupts disabled: this is bad for ++ * interrupt latency, but anything else has led to problems on some ++ * machines. ++ * ++ * We enable interrupts in some of the routines after making sure it's ++ * safe. ++ */ ++ ++ static int __init hd_init(void) ++ { ++ int drive; ++ ++ printk("%s:%d MAJOR_NR %d\n", __FUNCTION__, __LINE__, MAJOR_NR); ++ ++ if (register_blkdev(MAJOR_NR,"hd")) ++ return -1; ++ ++ reg_base = (unsigned char *) ioremap_nocache(CPLD_ATA_REG_BASE, 0x1000); ++ if (!reg_base) { ++ printk("%s:%d\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ /* If no card present, return */ ++ if (!cfide_card_present()) { ++ printk("No CompactFlash card detected\n"); ++ iounmap(reg_base); ++ return 0; ++ } ++ ++ /* Fetchthe device info */ ++ cfide_fetch_info(); ++ ++ hd_queue = blk_init_queue(do_hd_request, &hd_lock); ++ printk("%s:%d hd_queue %p\n", __FUNCTION__, __LINE__, hd_queue); ++ if (!hd_queue) { ++ unregister_blkdev(MAJOR_NR,"hd"); ++ return -ENOMEM; ++ } ++ ++ ++ blk_queue_max_sectors(hd_queue, 255); ++ blk_queue_hardsect_size(hd_queue, 512); ++ ++ #if 1 ++ hd_info[0].cyl = info_buf.id.cyls; ++ hd_info[0].head = info_buf.id.heads; ++ hd_info[0].wpcom = 0; ++ hd_info[0].ctl = 0; ++ hd_info[0].lzone = 0; ++ hd_info[0].sect = info_buf.id.sectors; ++ NR_HD++; ++ ++ printk("%s:%d NR_HD %d\n", __FUNCTION__, __LINE__, NR_HD); ++ ++ #else ++ #ifdef __i386__ ++ if (!NR_HD) { ++ extern struct drive_info drive_info; ++ unsigned char *BIOS = (unsigned char *) &drive_info; ++ unsigned long flags; ++ int cmos_disks; ++ ++ for (drive=0 ; drive<2 ; drive++) { ++ hd_info[drive].cyl = *(unsigned short *) BIOS; ++ hd_info[drive].head = *(2+BIOS); ++ hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); ++ hd_info[drive].ctl = *(8+BIOS); ++ hd_info[drive].lzone = *(unsigned short *) (12+BIOS); ++ hd_info[drive].sect = *(14+BIOS); ++ #ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp ++ if (hd_info[drive].cyl && NR_HD == drive) ++ NR_HD++; ++ #endif ++ BIOS += 16; ++ } ++ ++ /* ++ We query CMOS about hard disks : it could be that ++ we have a SCSI/ESDI/etc controller that is BIOS ++ compatible with ST-506, and thus showing up in our ++ BIOS table, but not register compatible, and therefore ++ not present in CMOS. ++ ++ Furthermore, we will assume that our ST-506 drives ++ <if any> are the primary drives in the system, and ++ the ones reflected as drive 1 or 2. ++ ++ The first drive is stored in the high nibble of CMOS ++ byte 0x12, the second in the low nibble. This will be ++ either a 4 bit drive type or 0xf indicating use byte 0x19 ++ for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. ++ ++ Needless to say, a non-zero value means we have ++ an AT controller hard disk for that drive. ++ ++ Currently the rtc_lock is a bit academic since this ++ driver is non-modular, but someday... ? Paul G. ++ */ ++ ++ spin_lock_irqsave(&rtc_lock, flags); ++ cmos_disks = CMOS_READ(0x12); ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ if (cmos_disks & 0xf0) { ++ if (cmos_disks & 0x0f) ++ NR_HD = 2; ++ else ++ NR_HD = 1; ++ } ++ } ++ #endif /* __i386__ */ ++ #ifdef __arm__ ++ if (!NR_HD) { ++ /* We don't know anything about the drive. This means ++ * that you *MUST* specify the drive parameters to the ++ * kernel yourself. ++ */ ++ printk("hd: no drives specified - use hd=cyl,head,sectors" ++ " on kernel command line\n"); ++ } ++ #endif ++ #endif ++ if (!NR_HD) ++ goto out; ++ ++ for (drive=0 ; drive < NR_HD ; drive++) { ++ struct gendisk *disk = alloc_disk(64); ++ struct hd_i_struct *p = &hd_info[drive]; ++ if (!disk) ++ goto Enomem; ++ disk->major = MAJOR_NR; ++ disk->first_minor = drive << 6; ++ disk->fops = &hd_fops; ++ sprintf(disk->disk_name, "hd%c", 'a'+drive); ++ disk->private_data = p; ++ set_capacity(disk, p->head * p->sect * p->cyl); ++ disk->queue = hd_queue; ++ p->unit = drive; ++ hd_gendisk[drive] = disk; ++ printk ("%s: %luMB, CHS=%d/%d/%d\n", ++ disk->disk_name, (unsigned long)get_capacity(disk)/2048, ++ p->cyl, p->head, p->sect); ++ } ++ ++ /* Let them fly */ ++ for(drive=0; drive < NR_HD; drive++) ++ add_disk(hd_gendisk[drive]); ++ ++ return 0; ++ ++ out: ++ unregister_blkdev(MAJOR_NR,"hd"); ++ blk_cleanup_queue(hd_queue); ++ return -1; ++ Enomem: ++ while (drive--) ++ put_disk(hd_gendisk[drive]); ++ goto out; ++ } ++ ++ static int __init parse_hd_setup (char *line) { ++ int ints[6]; ++ ++ (void) get_options(line, ARRAY_SIZE(ints), ints); ++ hd_setup(NULL, ints); ++ ++ return 1; ++ } ++ __setup("hd=", parse_hd_setup); ++ ++ module_init(hd_init); ++ ++ /* ++ * Local variables: ++ * c-indent-level: 4 ++ * tab-width: 4 ++ * End: ++ */ |