diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking --- a/Documentation/filesystems/Locking Sun May 5 20:39:49 2002 +++ b/Documentation/filesystems/Locking Sun May 5 20:39:49 2002 @@ -137,6 +137,9 @@ int (*writepage)(struct page *); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); + int (*writeback_mapping)(struct address_space *, int *nr_to_write); + int (*vm_writeback)(struct page *, int *nr_to_write); + int (*set_page_dirty)(struct page *page); int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); int (*bmap)(struct address_space *, long); @@ -145,32 +148,71 @@ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); locking rules: - All may block - BKL PageLocked(page) -writepage: no yes, unlocks -readpage: no yes, unlocks -sync_page: no maybe -prepare_write: no yes -commit_write: no yes -bmap: yes -flushpage: no yes -releasepage: no yes + All except set_page_dirty may block + + BKL PageLocked(page) +writepage: no yes, unlocks +readpage: no yes, unlocks +sync_page: no maybe +writeback_mapping: no +vm_writeback: no yes +set_page_dirty no no +prepare_write: no yes +commit_write: no yes +bmap: yes +flushpage: no yes +releasepage: no yes ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop). - ->readpage() and ->writepage() unlock the page. + + ->readpage() unlocks the page, either synchronously or via I/O +completion. + + ->writepage() unlocks the page synchronously, before returning to +the caller. If the page has write I/O underway against it, writepage() +should run SetPageWriteback() against the page prior to unlocking it. +The write I/O completion handler should run ClearPageWriteback against +the page. + + That is: after 2.5.12, pages which are under writeout are *not* +locked. + ->sync_page() locking rules are not well-defined - usually it is called with lock on page, but that is not guaranteed. Considering the currently existing instances of this method ->sync_page() itself doesn't look well-defined... + + ->writeback_mapping() is used for periodic writeback and for +systemcall-initiated sync operations. The address_space should start +I/O against at least *nr_to_write pages. *nr_to_write must be decremented +for each page which is written. *nr_to_write must not go negative (this +will be relaxed later). If nr_to_write is NULL, all dirty pages must +be written. + + ->vm_writeback() is called from the VM. The address_space should +start I/O against at least *nr_to_write pages, including the passed page. As +each page is written its PG_launder flag must be set (inside the page lock). + + The vm_writeback() function is provided so that filesytems can perform +clustered writeback around the page which the VM is trying to clean. +If a_ops.vm_writeback is NULL the VM will fall back to single-page writepage(). + + ->set_page_dirty() is called from various places in the kernel +when the target page is marked as needing writeback. It may be called +under spinlock (it cannot block) and is sometimes called with the page +not locked. + ->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some filesystems and by the swapper. The latter will eventually go away. All instances do not actually need the BKL. Please, keep it that way and don't breed new callers. + ->flushpage() is called when the filesystem must attempt to drop some or all of the buffers from the page when it is being truncated. It returns zero on success. If ->flushpage is zero, the kernel uses block_flushpage() instead. + ->releasepage() is called when the kernel is about to try to drop the buffers from the page in preparation for freeing it. It returns zero to indicate that the buffers are (or may be) freeable. If ->releasepage is zero, diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt Sun May 5 20:39:50 2002 +++ b/Documentation/filesystems/ntfs.txt Sun May 5 20:39:50 2002 @@ -262,6 +262,13 @@ Note that a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.0.6: + - Major bugfix to make compatible with other kernel changes. This fixes + the hangs/oopses on umount. + - Locking cleanup in directory operations (remove BKL usage). +2.0.5: + - Major buffer overflow bug fix. + - Minor cleanups and updates for kernel 2.5.12. 2.0.4: - Cleanups and updates for kernel 2.5.11. 2.0.3: diff -Nru a/Documentation/i810_rng.txt b/Documentation/i810_rng.txt --- a/Documentation/i810_rng.txt Sun May 5 20:39:50 2002 +++ b/Documentation/i810_rng.txt Sun May 5 20:39:50 2002 @@ -70,6 +70,9 @@ Change history: + Version 0.9.8: + * Support other i8xx chipsets by adding 82801E detection + Version 0.9.7: * Support other i8xx chipsets too (by adding 82801BA(M) and 82801CA(M) detection) diff -Nru a/Makefile b/Makefile --- a/Makefile Sun May 5 20:39:49 2002 +++ b/Makefile Sun May 5 20:39:49 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 13 +SUBLEVEL = 14 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in --- a/arch/alpha/config.in Sun May 5 20:39:49 2002 +++ b/arch/alpha/config.in Sun May 5 20:39:49 2002 @@ -372,9 +372,7 @@ source drivers/usb/Config.in source drivers/input/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c --- a/arch/alpha/kernel/core_irongate.c Sun May 5 20:39:49 2002 +++ b/arch/alpha/kernel/core_irongate.c Sun May 5 20:39:49 2002 @@ -421,6 +421,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -428,17 +429,17 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("irongate_remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, - mk_pte_phys(phys_addr, - __pgprot(_PAGE_VALID | _PAGE_ASM | - _PAGE_KRE | _PAGE_KWE | flags))); + set_pte(pte, pfn_pte(pfn, + __pgprot(_PAGE_VALID | _PAGE_ASM | + _PAGE_KRE | _PAGE_KWE | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c --- a/arch/alpha/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/alpha/mm/init.c Sun May 5 20:39:49 2002 @@ -36,8 +36,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -unsigned long totalram_pages; - extern void die_if_kernel(char *,struct pt_regs *,long); static struct pcb_struct original_pcb; @@ -250,12 +248,12 @@ /* Set up the third level PTEs and update the virtual addresses of the CRB entries. */ for (i = 0; i < crb->map_entries; ++i) { - unsigned long paddr = crb->map[i].pa; + unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT; crb->map[i].va = vaddr; for (j = 0; j < crb->map[i].count; ++j) { set_pte(pte_offset_kernel(pmd, vaddr), - mk_pte_phys(paddr, PAGE_KERNEL)); - paddr += PAGE_SIZE; + pfn_pte(pfn, PAGE_KERNEL)); + pfn++; vaddr += PAGE_SIZE; } } @@ -390,15 +388,3 @@ printk ("Freeing initrd memory: %ldk freed\n", (end - __start) >> 10); } #endif - -void -si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; -} diff -Nru a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c --- a/arch/alpha/mm/numa.c Sun May 5 20:39:49 2002 +++ b/arch/alpha/mm/numa.c Sun May 5 20:39:49 2002 @@ -358,7 +358,6 @@ extern int page_is_ram(unsigned long) __init; extern char _text, _etext, _data, _edata; extern char __init_begin, __init_end; - extern unsigned long totalram_pages; unsigned long nid, i; mem_map_t * lmem_map; diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Sun May 5 20:39:49 2002 +++ b/arch/arm/config.in Sun May 5 20:39:49 2002 @@ -655,9 +655,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/arm/mach-arc/mm.c b/arch/arm/mach-arc/mm.c --- a/arch/arm/mach-arc/mm.c Sun May 5 20:39:49 2002 +++ b/arch/arm/mach-arc/mm.c Sun May 5 20:39:49 2002 @@ -138,7 +138,7 @@ page_nr = max_low_pfn; pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); - pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); + pte[0] = pfn_pte((PAGE_OFFSET + 491520) >> PAGE_SHIFT, PAGE_READONLY); pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte); for (i = 1; i < PTRS_PER_PGD; i++) diff -Nru a/arch/arm/mach-arc/small_page.c b/arch/arm/mach-arc/small_page.c --- a/arch/arm/mach-arc/small_page.c Sun May 5 20:39:49 2002 +++ b/arch/arm/mach-arc/small_page.c Sun May 5 20:39:49 2002 @@ -150,8 +150,8 @@ unsigned long flags; struct page *page; - page = virt_to_page(spage); - if (VALID_PAGE(page)) { + if (virt_addr_valid(spage)) { + page = virt_to_page(spage); /* * The container-page must be marked Reserved diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c --- a/arch/arm/mm/fault-armv.c Sun May 5 20:39:49 2002 +++ b/arch/arm/mm/fault-armv.c Sun May 5 20:39:49 2002 @@ -240,9 +240,13 @@ */ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) { - struct page *page = pte_page(pte); + unsigned long pfn = pte_pfn(pte); + struct page *page; - if (VALID_PAGE(page) && page->mapping) { + if (!pfn_valid(pfn)) + return; + page = pfn_to_page(pfn); + if (page->mapping) { if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) __flush_dcache_page(page); diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c --- a/arch/arm/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/arm/mm/init.c Sun May 5 20:39:49 2002 @@ -48,7 +48,6 @@ #define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(pte_t)) -static unsigned long totalram_pages; extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern char _stext, _text, _etext, _end, __init_begin, __init_end; @@ -631,14 +630,3 @@ __setup("keepinitrd", keepinitrd_setup); #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; -} diff -Nru a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c --- a/arch/arm/mm/ioremap.c Sun May 5 20:39:50 2002 +++ b/arch/arm/mm/ioremap.c Sun May 5 20:39:50 2002 @@ -51,7 +51,7 @@ printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot)); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; diff -Nru a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c --- a/arch/arm/mm/minicache.c Sun May 5 20:39:49 2002 +++ b/arch/arm/mm/minicache.c Sun May 5 20:39:49 2002 @@ -43,7 +43,7 @@ */ unsigned long map_page_minicache(unsigned long virt) { - set_pte(minicache_pte, mk_pte_phys(__pa(virt), minicache_pgprot)); + set_pte(minicache_pte, pfn_pte(__pa(virt) >> PAGE_SHIFT, minicache_pgprot)); flush_tlb_kernel_page(minicache_address); return minicache_address; diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c --- a/arch/arm/mm/mm-armv.c Sun May 5 20:39:50 2002 +++ b/arch/arm/mm/mm-armv.c Sun May 5 20:39:50 2002 @@ -198,7 +198,7 @@ } ptep = pte_offset_kernel(pmdp, virt); - set_pte(ptep, mk_pte_phys(phys, __pgprot(prot))); + set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, __pgprot(prot))); } /* diff -Nru a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c --- a/arch/cris/drivers/ide.c Sun May 5 20:39:49 2002 +++ b/arch/cris/drivers/ide.c Sun May 5 20:39:49 2002 @@ -191,7 +191,7 @@ #define ATA_PIO0_STROBE 19 #define ATA_PIO0_HOLD 4 -static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); +static int e100_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq); static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, void *buffer, unsigned int length); @@ -278,7 +278,7 @@ hwif->chipset = ide_etrax100; hwif->tuneproc = &tune_e100_ide; - hwif->dmaproc = &e100_dmaproc; + hwif->udma = &e100_dmaproc; hwif->ata_read = e100_ide_input_data; hwif->ata_write = e100_ide_output_data; hwif->atapi_read = e100_atapi_read; @@ -564,13 +564,14 @@ static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS]; static unsigned int ata_tot_size; + /* - * e100_ide_build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. + * This prepares a dma request. Returns 0 if all went okay, returns 1 + * otherwise. */ -static int e100_ide_build_dmatable (ide_drive_t *drive) + +static int e100_udma_new_table(struct ata_channel *ch, struct request *rq) { - struct request *rq = HWGROUP(drive)->rq; struct buffer_head *bh = rq->bh; unsigned long size, addr; unsigned int count = 0; @@ -602,7 +603,7 @@ /* did we run out of descriptors? */ if(count >= MAX_DMA_DESCRS) { - printk("%s: too few DMA descriptors\n", drive->name); + printk("%s: too few DMA descriptors\n", ch->name); return 1; } @@ -623,7 +624,7 @@ size > 131072 only one split is necessary */ if(size > 65536) { - /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ ata_descrs[count].ctrl = 0; ata_descrs[count].buf = addr; @@ -656,7 +657,7 @@ return 0; } - printk("%s: empty DMA table?\n", drive->name); + printk("%s: empty DMA table?\n", ch->name); return 1; /* let the PIO routines handle this weirdness */ } @@ -695,7 +696,7 @@ LED_DISK_READ(0); LED_DISK_WRITE(0); - dma_stat = drive->channel->dmaproc(ide_dma_end, drive); + dma_stat = drive->channel->udma(ide_dma_end, drive, rq); stat = GET_STAT(); /* get drive status */ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { if (!dma_stat) { @@ -726,7 +727,7 @@ * the caller should revert to PIO for the current request. */ -static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +static int e100_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) { static unsigned int reading; /* static to support ide_dma_begin semantics */ int atapi = 0; @@ -786,24 +787,21 @@ /* set up the Etrax DMA descriptors */ - if(e100_ide_build_dmatable (drive)) + if(e100_udma_new_table(drive->channel, rq)) return 1; if(!atapi) { /* set the irq handler which will finish the request when DMA is done */ - ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - + /* issue cmd to drive */ - OUT_BYTE(WIN_READDMA, IDE_COMMAND_REG); } /* begin DMA */ - *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs); *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - + /* initiate a multi word dma read using DMA handshaking */ *R_ATA_TRANSFER_CNT = @@ -820,7 +818,7 @@ LED_DISK_READ(1); D(printk("dma read of %d bytes.\n", ata_tot_size)); - + } else { /* writing */ @@ -829,29 +827,25 @@ /* set up the Etrax DMA descriptors */ - if(e100_ide_build_dmatable (drive)) + if(e100_udma_new_table(drive->channel, rq)) return 1; if(!atapi) { /* set the irq handler which will finish the request when DMA is done */ - ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - + /* issue cmd to drive */ - OUT_BYTE(WIN_WRITEDMA, IDE_COMMAND_REG); } /* begin DMA */ - *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs); *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - + /* initiate a multi word dma write using DMA handshaking */ - *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); - + *R_ATA_CTRL_DATA = IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | IO_STATE(R_ATA_CTRL_DATA, rw, write) | @@ -878,7 +872,7 @@ * --- Marcin Dalecki */ -void ide_release_dma(struct ata_channel *hwif) +void ide_release_dma(struct ata_channel *ch) { /* empty */ } diff -Nru a/arch/cris/mm/init.c b/arch/cris/mm/init.c --- a/arch/cris/mm/init.c Sun May 5 20:39:50 2002 +++ b/arch/cris/mm/init.c Sun May 5 20:39:50 2002 @@ -114,8 +114,6 @@ #include #include -static unsigned long totalram_pages; - struct pgtable_cache_struct quicklists; /* see asm/pgalloc.h */ const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; @@ -470,16 +468,4 @@ } printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10); -} - -void -si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; } diff -Nru a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c --- a/arch/cris/mm/ioremap.c Sun May 5 20:39:49 2002 +++ b/arch/cris/mm/ioremap.c Sun May 5 20:39:49 2002 @@ -17,6 +17,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -24,16 +25,17 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | - __WRITEABLE | _PAGE_GLOBAL | - _PAGE_KERNEL | flags))); + set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | __READABLE | + __WRITEABLE | _PAGE_GLOBAL | + _PAGE_KERNEL | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Sun May 5 20:39:49 2002 +++ b/arch/i386/config.in Sun May 5 20:39:49 2002 @@ -392,9 +392,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c --- a/arch/i386/kernel/acpi.c Sun May 5 20:39:50 2002 +++ b/arch/i386/kernel/acpi.c Sun May 5 20:39:50 2002 @@ -550,7 +550,7 @@ /* fill page with low mapping */ for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(ptep + i, mk_pte_phys(i << PAGE_SHIFT, PAGE_SHARED)); + set_pte(ptep + i, pfn_pte(i, PAGE_SHARED)); pgd = pgd_offset(current->active_mm, 0); pmd = pmd_alloc(current->mm,pgd, 0); diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/i386/mm/init.c Sun May 5 20:39:49 2002 @@ -41,8 +41,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; -static unsigned long totalram_pages; -static unsigned long totalhigh_pages; /* * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the @@ -122,7 +120,7 @@ } pte = pte_offset_kernel(pmd, vaddr); /* stored as-is, to permit clearing entries */ - set_pte(pte, mk_pte_phys(phys, flags)); + set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); /* * It's enough to flush this one mapping. @@ -239,7 +237,7 @@ vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; if (end && (vaddr >= end)) break; - *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); + *pte = pfn_pte(__pa(vaddr) >> PAGE_SHIFT, PAGE_KERNEL); } set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); if (pte_base != pte_offset_kernel(pmd, 0)) @@ -375,7 +373,7 @@ pmd = pmd_offset(pgd, vaddr); pte = pte_offset_kernel(pmd, vaddr); old_pte = *pte; - *pte = mk_pte_phys(0, PAGE_READONLY); + *pte = pfn_pte(0, PAGE_READONLY); local_flush_tlb(); boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr); @@ -560,18 +558,6 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; - return; -} #if defined(CONFIG_X86_PAE) static struct kmem_cache_s *pae_pgd_cachep; diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c --- a/arch/i386/mm/ioremap.c Sun May 5 20:39:49 2002 +++ b/arch/i386/mm/ioremap.c Sun May 5 20:39:49 2002 @@ -20,6 +20,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -27,15 +28,16 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | + set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in --- a/arch/ia64/config.in Sun May 5 20:39:50 2002 +++ b/arch/ia64/config.in Sun May 5 20:39:50 2002 @@ -226,9 +226,7 @@ source lib/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in fi # !HP_SIM diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c Sun May 5 20:39:49 2002 +++ b/arch/ia64/kernel/efi.c Sun May 5 20:39:49 2002 @@ -268,7 +268,7 @@ */ ia64_clear_ic(flags); ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), IA64_GRANULE_SHIFT); + pte_val(pfn_pte(md->phys_addr >> PAGE_SHIFT, PAGE_KERNEL)), IA64_GRANULE_SHIFT); local_irq_restore(flags); ia64_srlz_i(); } diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/ia64/mm/init.c Sun May 5 20:39:49 2002 @@ -36,8 +36,6 @@ unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; -static unsigned long totalram_pages; - static int pgt_cache_water[2] = { 25, 50 }; void @@ -109,6 +107,7 @@ void free_initrd_mem (unsigned long start, unsigned long end) { + struct page *page; /* * EFI uses 4KB pages while the kernel can use 4KB or bigger. * Thus EFI and the kernel may have different page sizes. It is @@ -147,29 +146,17 @@ printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { - if (!VALID_PAGE(virt_to_page(start))) + if (!virt_addr_valid(start)) continue; - clear_bit(PG_reserved, &virt_to_page(start)->flags); - set_page_count(virt_to_page(start), 1); - free_page(start); + page = virt_to_page(start); + clear_bit(PG_reserved, &page->flags); + set_page_count(page, 1); + __free_page(page); ++totalram_pages; } } void -si_meminfo (struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; - return; -} - -void show_mem(void) { int i, total = 0, reserved = 0; @@ -289,7 +276,7 @@ ia64_srlz_d(); ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT); + pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PAGE_SHIFT); __restore_flags(flags); ia64_srlz_i(); diff -Nru a/arch/ia64/sn/kernel/misctest.c b/arch/ia64/sn/kernel/misctest.c --- a/arch/ia64/sn/kernel/misctest.c Sun May 5 20:39:50 2002 +++ b/arch/ia64/sn/kernel/misctest.c Sun May 5 20:39:50 2002 @@ -89,7 +89,7 @@ printk("zzzspec: probe %ld, 0x%lx\n", res, val); ia64_clear_ic(flags); ia64_itc(0x2, 0xe00000ff00000000UL, - pte_val(mk_pte_phys(0xff00000000UL, + pte_val(pfn_pte(0xff00000000UL >> PAGE_SHIFT, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M); local_irq_restore(flags); ia64_srlz_i (); diff -Nru a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c --- a/arch/m68k/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/m68k/mm/init.c Sun May 5 20:39:49 2002 @@ -35,8 +35,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -unsigned long totalram_pages = 0; - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -202,18 +200,3 @@ printk ("Freeing initrd memory: %dk freed\n", pages); } #endif - -void si_meminfo(struct sysinfo *val) -{ - unsigned long i; - - i = max_mapnr; - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; - return; -} diff -Nru a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c --- a/arch/m68k/mm/motorola.c Sun May 5 20:39:50 2002 +++ b/arch/m68k/mm/motorola.c Sun May 5 20:39:50 2002 @@ -286,7 +286,6 @@ } extern char __init_begin, __init_end; -extern unsigned long totalram_pages; void free_initmem(void) { diff -Nru a/arch/mips/gt64120/momenco_ocelot/setup.c b/arch/mips/gt64120/momenco_ocelot/setup.c --- a/arch/mips/gt64120/momenco_ocelot/setup.c Sun May 5 20:39:50 2002 +++ b/arch/mips/gt64120/momenco_ocelot/setup.c Sun May 5 20:39:50 2002 @@ -78,7 +78,7 @@ static char reset_reason; -#define ENTRYLO(x) ((pte_val(mk_pte_phys((x), PAGE_KERNEL_UNCACHED)) >> 6)|1) +#define ENTRYLO(x) ((pte_val(pfn_pte((x) >> PAGE_SHIFT, PAGE_KERNEL_UNCACHED)) >> 6)|1) static void __init setup_l3cache(unsigned long size); diff -Nru a/arch/mips/mm/init.c b/arch/mips/mm/init.c --- a/arch/mips/mm/init.c Sun May 5 20:39:50 2002 +++ b/arch/mips/mm/init.c Sun May 5 20:39:50 2002 @@ -45,8 +45,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -static unsigned long totalram_pages; - extern void prom_free_prom_memory(void); @@ -264,17 +262,4 @@ } printk("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); -} - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = atomic_read(&shmem_nrpages); - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; - - return; } diff -Nru a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c --- a/arch/mips/mm/ioremap.c Sun May 5 20:39:50 2002 +++ b/arch/mips/mm/ioremap.c Sun May 5 20:39:50 2002 @@ -18,6 +18,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE | __WRITEABLE | flags); @@ -27,14 +28,15 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + set_pte(pte, pfn_pte(pfn, pgprot)); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/mips/mm/umap.c b/arch/mips/mm/umap.c --- a/arch/mips/mm/umap.c Sun May 5 20:39:50 2002 +++ b/arch/mips/mm/umap.c Sun May 5 20:39:50 2002 @@ -116,8 +116,12 @@ static inline void free_pte(pte_t page) { if (pte_present(page)) { - struct page *ptpage = pte_page(page); - if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) + unsigned long pfn = pte_pfn(page); + struct page *ptpage; + if (!pfn_valid(pfn)) + return; + ptpage = pfn_to_page(pfn); + if (PageReserved(ptpage)) return; __free_page(ptpage); if (current->mm->rss <= 0) diff -Nru a/arch/mips64/mm/init.c b/arch/mips64/mm/init.c --- a/arch/mips64/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/mips64/mm/init.c Sun May 5 20:39:49 2002 @@ -40,8 +40,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -unsigned long totalram_pages; - void pgd_init(unsigned long page) { unsigned long *p, *end; @@ -457,18 +455,4 @@ } printk("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); -} - -void -si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = atomic_read(&shmem_nrpages); - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; - - return; } diff -Nru a/arch/mips64/mm/umap.c b/arch/mips64/mm/umap.c --- a/arch/mips64/mm/umap.c Sun May 5 20:39:49 2002 +++ b/arch/mips64/mm/umap.c Sun May 5 20:39:49 2002 @@ -115,8 +115,12 @@ static inline void free_pte(pte_t page) { if (pte_present(page)) { - struct page *ptpage = pte_page(page); - if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) + unsigned long pfn = pte_pfn(page); + struct page *ptpage; + if (!pfn_valid(pfn)) + return; + ptpage = pfn_to_page(pfn); + if (PageReserved(ptpage)) return; __free_page(ptpage); if (current->mm->rss <= 0) diff -Nru a/arch/mips64/sgi-ip27/ip27-memory.c b/arch/mips64/sgi-ip27/ip27-memory.c --- a/arch/mips64/sgi-ip27/ip27-memory.c Sun May 5 20:39:49 2002 +++ b/arch/mips64/sgi-ip27/ip27-memory.c Sun May 5 20:39:49 2002 @@ -265,7 +265,6 @@ { extern char _stext, _etext, _fdata, _edata; extern char __init_begin, __init_end; - extern unsigned long totalram_pages; extern unsigned long setup_zero_pages(void); cnodeid_t nid; unsigned long tmp; diff -Nru a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c --- a/arch/parisc/mm/init.c Sun May 5 20:39:50 2002 +++ b/arch/parisc/mm/init.c Sun May 5 20:39:50 2002 @@ -20,7 +20,6 @@ #include -static unsigned long totalram_pages; extern unsigned long max_pfn, mem_max; void free_initmem(void) { @@ -451,29 +450,3 @@ #endif } #endif - -void si_meminfo(struct sysinfo *val) -{ - int i; - - i = max_mapnr; - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); -#if 0 - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!atomic_read(&mem_map[i].count)) - continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; -#endif - val->totalhigh = 0; - val->freehigh = 0; - return; -} diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in --- a/arch/ppc/config.in Sun May 5 20:39:49 2002 +++ b/arch/ppc/config.in Sun May 5 20:39:49 2002 @@ -589,9 +589,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in source lib/Config.in diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c --- a/arch/ppc/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/ppc/mm/init.c Sun May 5 20:39:49 2002 @@ -70,8 +70,6 @@ int mem_init_done; int init_bootmem_done; int boot_mapsize; -unsigned long totalram_pages; -unsigned long totalhigh_pages; #ifdef CONFIG_ALL_PPC unsigned long agp_special_page; #endif @@ -143,17 +141,6 @@ printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld buffermem pages\n", nr_buffermem_pages()); -} - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; } /* Free up now-unused memory */ diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c --- a/arch/ppc/mm/pgtable.c Sun May 5 20:39:49 2002 +++ b/arch/ppc/mm/pgtable.c Sun May 5 20:39:49 2002 @@ -237,7 +237,7 @@ pg = pte_alloc_kernel(&init_mm, pd, va); if (pg != 0) { err = 0; - set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); + set_pte(pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); if (mem_init_done) flush_HPTE(0, va, pmd_val(*pd)); } diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c Sun May 5 20:39:50 2002 +++ b/arch/ppc64/mm/init.c Sun May 5 20:39:50 2002 @@ -73,7 +73,6 @@ unsigned long ioremap_bot = IMALLOC_BASE; static int boot_mapsize; -static unsigned long totalram_pages; extern pgd_t swapper_pg_dir[]; extern char __init_begin, __init_end; @@ -138,17 +137,6 @@ printk("%ld buffermem pages\n", nr_buffermem_pages()); } -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; -} - void * ioremap(unsigned long addr, unsigned long size) { @@ -240,7 +228,7 @@ ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea); pa = absolute_to_phys(pa); - set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); + set_pte(ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); spin_unlock(&ioremap_mm.page_table_lock); } else { /* If the mm subsystem is not fully up, we cannot create a diff -Nru a/arch/s390/mm/init.c b/arch/s390/mm/init.c --- a/arch/s390/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/s390/mm/init.c Sun May 5 20:39:49 2002 @@ -39,8 +39,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -static unsigned long totalram_pages; - pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); @@ -118,9 +116,8 @@ pte_t pte; int i; unsigned long tmp; - unsigned long address=0; + unsigned long pfn = 0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; - unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE); static const int ssm_mask = 0x04000000L; /* unmap whole virtual address space */ @@ -136,7 +133,7 @@ pg_dir = swapper_pg_dir; - while (address < end_mem) { + while (pfn < max_low_pfn) { /* * pg_table is physical at this point */ @@ -149,11 +146,11 @@ pg_dir++; for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { - pte = mk_pte_phys(address, PAGE_KERNEL); - if (address >= end_mem) + pte = pfn_pte(pfn, PAGE_KERNEL); + if (pfn >= max_low_pfn) pte_clear(&pte); set_pte(pg_table, pte); - address += PAGE_SIZE; + pfn++; } } @@ -231,14 +228,3 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; -} diff -Nru a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c --- a/arch/s390/mm/ioremap.c Sun May 5 20:39:49 2002 +++ b/arch/s390/mm/ioremap.c Sun May 5 20:39:49 2002 @@ -21,6 +21,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -28,15 +29,15 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, - __pgprot(_PAGE_PRESENT | flags))); + set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/s390x/mm/init.c b/arch/s390x/mm/init.c --- a/arch/s390x/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/s390x/mm/init.c Sun May 5 20:39:49 2002 @@ -39,8 +39,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -static unsigned long totalram_pages; - pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); @@ -116,10 +114,9 @@ pte_t * pt_dir; pte_t pte; int i,j,k; - unsigned long address=0; + unsigned long pfn = 0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; - unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE); static const int ssm_mask = 0x04000000L; unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; @@ -147,7 +144,7 @@ for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) { - if (address >= end_mem) { + if (pfn >= max_low_pfn) { pgd_clear(pg_dir); continue; } @@ -156,7 +153,7 @@ pgd_populate(&init_mm, pg_dir, pm_dir); for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) { - if (address >= end_mem) { + if (pfn >= max_low_pfn) { pmd_clear(pm_dir); continue; } @@ -165,13 +162,13 @@ pmd_populate(&init_mm, pm_dir, pt_dir); for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) { - pte = mk_pte_phys(address, PAGE_KERNEL); - if (address >= end_mem) { + pte = mk_pte_phys(pfn, PAGE_KERNEL); + if (pfn >= max_low_pfn) { pte_clear(&pte); continue; } set_pte(pt_dir, pte); - address += PAGE_SIZE; + pfn++; } } } @@ -243,17 +240,6 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = 0; - val->mem_unit = PAGE_SIZE; -} /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -Nru a/arch/s390x/mm/ioremap.c b/arch/s390x/mm/ioremap.c --- a/arch/s390x/mm/ioremap.c Sun May 5 20:39:50 2002 +++ b/arch/s390x/mm/ioremap.c Sun May 5 20:39:50 2002 @@ -21,6 +21,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -28,15 +29,15 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, - __pgprot(_PAGE_PRESENT | flags))); + set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c --- a/arch/sh/mm/cache-sh4.c Sun May 5 20:39:49 2002 +++ b/arch/sh/mm/cache-sh4.c Sun May 5 20:39:49 2002 @@ -398,7 +398,7 @@ pte_t entry; unsigned long flags; - entry = mk_pte_phys(phys_addr, pgprot); + entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot); down(&p3map_sem[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); save_and_cli(flags); @@ -437,7 +437,7 @@ pte_t entry; unsigned long flags; - entry = mk_pte_phys(phys_addr, pgprot); + entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot); down(&p3map_sem[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); save_and_cli(flags); diff -Nru a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c --- a/arch/sh/mm/fault.c Sun May 5 20:39:49 2002 +++ b/arch/sh/mm/fault.c Sun May 5 20:39:49 2002 @@ -290,6 +290,7 @@ unsigned long vpn; #if defined(__SH4__) struct page *page; + unsigned long pfn; unsigned long ptea; #endif @@ -298,11 +299,14 @@ return; #if defined(__SH4__) - page = pte_page(pte); - if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); + pfn = pte_pfn(pte); + if (pfn_valid(pfn)) { + page = pfn_to_page(pfn); + if (!test_bit(PG_mapped, &page->flags)) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; + __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); + __set_bit(PG_mapped, &page->flags); + } } #endif diff -Nru a/arch/sh/mm/init.c b/arch/sh/mm/init.c --- a/arch/sh/mm/init.c Sun May 5 20:39:50 2002 +++ b/arch/sh/mm/init.c Sun May 5 20:39:50 2002 @@ -48,9 +48,6 @@ bootmem_data_t discontig_node_bdata[NR_NODES]; #endif -static unsigned long totalram_pages; -static unsigned long totalhigh_pages; - void show_mem(void) { int i, total = 0, reserved = 0; @@ -203,15 +200,3 @@ printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; - return; -} diff -Nru a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c --- a/arch/sh/mm/ioremap.c Sun May 5 20:39:49 2002 +++ b/arch/sh/mm/ioremap.c Sun May 5 20:39:49 2002 @@ -17,6 +17,7 @@ unsigned long size, unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | flags); @@ -27,14 +28,15 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + set_pte(pte, pfn_pte(pfn, pgprot)); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c --- a/arch/sparc/kernel/sun4d_smp.c Sun May 5 20:39:49 2002 +++ b/arch/sparc/kernel/sun4d_smp.c Sun May 5 20:39:49 2002 @@ -63,8 +63,6 @@ extern volatile int smp_commenced; extern int __smp4d_processor_id(void); -extern unsigned long totalram_pages; - /* #define SMP_DEBUG */ #ifdef SMP_DEBUG diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c --- a/arch/sparc/kernel/sun4m_smp.c Sun May 5 20:39:49 2002 +++ b/arch/sparc/kernel/sun4m_smp.c Sun May 5 20:39:49 2002 @@ -59,8 +59,6 @@ extern volatile int smp_commenced; extern int __smp4m_processor_id(void); -extern unsigned long totalram_pages; - /*#define SMP_DEBUG*/ #ifdef SMP_DEBUG diff -Nru a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c --- a/arch/sparc/mm/generic.c Sun May 5 20:39:50 2002 +++ b/arch/sparc/mm/generic.c Sun May 5 20:39:50 2002 @@ -19,8 +19,12 @@ if (pte_none(page)) return; if (pte_present(page)) { - struct page *ptpage = pte_page(page); - if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) + unsigned long pfn = pte_pfn(page); + struct page *ptpage; + if (!pfn_valid(pfn)) + return; + ptpage = pfn_to_page(pfn); + if (PageReserved(ptpage)) return; page_cache_release(ptpage); return; diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c --- a/arch/sparc/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/sparc/mm/init.c Sun May 5 20:39:49 2002 @@ -55,8 +55,6 @@ extern unsigned int sparc_ramdisk_size; unsigned long highstart_pfn, highend_pfn; -unsigned long totalram_pages; -unsigned long totalhigh_pages; pte_t *kmap_pte; pgprot_t kmap_prot; @@ -504,18 +502,6 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - - val->mem_unit = PAGE_SIZE; -} void flush_page_to_ram(struct page *page) { diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c --- a/arch/sparc/mm/srmmu.c Sun May 5 20:39:49 2002 +++ b/arch/sparc/mm/srmmu.c Sun May 5 20:39:49 2002 @@ -1105,7 +1105,6 @@ extern void sparc_context_init(int); extern int linux_num_cpus; -extern unsigned long totalhigh_pages; void (*poke_srmmu)(void) __initdata = NULL; @@ -2043,7 +2042,7 @@ BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_SWAPO0G0); BTFIXUPSET_CALL(mk_pte, srmmu_mk_pte, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte_phys, srmmu_mk_pte_phys, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pfn_pte, srmmu_pfn_pte, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mk_pte_io, srmmu_mk_pte_io, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM); diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c --- a/arch/sparc/mm/sun4c.c Sun May 5 20:39:49 2002 +++ b/arch/sparc/mm/sun4c.c Sun May 5 20:39:49 2002 @@ -1327,7 +1327,7 @@ unsigned long page; page = ((unsigned long)bufptr) & PAGE_MASK; - if (!VALID_PAGE(virt_to_page(page))) { + if (!virt_addr_valid(page)) { sun4c_flush_page(page); return (__u32)bufptr; /* already locked */ } @@ -2106,7 +2106,7 @@ static int sun4c_pmd_bad(pmd_t pmd) { return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) || - (!VALID_PAGE(virt_to_page(pmd_val(pmd))))); + (!virt_addr_valid(pmd_val(pmd)))); } static int sun4c_pmd_present(pmd_t pmd) @@ -2526,7 +2526,7 @@ BTFIXUPSET_CALL(pgd_clear, sun4c_pgd_clear, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(mk_pte, sun4c_mk_pte, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte_phys, sun4c_mk_pte_phys, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pfn_pte, sun4c_pfn_pte, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM); BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in --- a/arch/sparc64/config.in Sun May 5 20:39:49 2002 +++ b/arch/sparc64/config.in Sun May 5 20:39:49 2002 @@ -267,9 +267,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Watchdog' diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c Sun May 5 20:39:50 2002 +++ b/arch/sparc64/kernel/traps.c Sun May 5 20:39:50 2002 @@ -1312,10 +1312,8 @@ } if (recoverable) { - struct page *page = virt_to_page(__va(afar)); - - if (VALID_PAGE(page)) - get_page(page); + if (pfn_valid(afar >> PAGE_SHIFT)) + get_page(pfn_to_page(afar >> PAGE_SHIFT)); else recoverable = 0; diff -Nru a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c --- a/arch/sparc64/mm/generic.c Sun May 5 20:39:49 2002 +++ b/arch/sparc64/mm/generic.c Sun May 5 20:39:49 2002 @@ -20,8 +20,12 @@ if (pte_none(page)) return; if (pte_present(page)) { - struct page *ptpage = pte_page(page); - if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) + unsigned long pfn = pte_pfn(page); + struct page *ptpage; + if (!pfn_valid(pfn)) + return; + ptpage = pfn_to_page(page); + if (PageReserved(ptpage)) return; page_cache_release(ptpage); return; diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c --- a/arch/sparc64/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/sparc64/mm/init.c Sun May 5 20:39:49 2002 @@ -187,11 +187,13 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - struct page *page = pte_page(pte); + struct page *page; + unsigned long pfn; unsigned long pg_flags; - if (VALID_PAGE(page) && - page->mapping && + pfn = pte_pfn(pte); + if (pfn_valid(pfn) && + (page = pfn_to_page(pfn), page->mapping) && ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) { int cpu = ((pg_flags >> 24) & (NR_CPUS - 1UL)); @@ -260,10 +262,14 @@ continue; if (pte_present(pte) && pte_dirty(pte)) { - struct page *page = pte_page(pte); + struct page *page; unsigned long pgaddr, uaddr; + unsigned long pfn = pte_pfn(pte); - if (!VALID_PAGE(page) || PageReserved(page) || !page->mapping) + if (!pfn_valid(pfn)) + continue; + page = pfn_to_page(pfn); + if (PageReserved(page) || !page->mapping) continue; pgaddr = (unsigned long) page_address(page); uaddr = address + offset; @@ -1784,17 +1790,3 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = num_physpages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - - /* These are always zero on Sparc64. */ - val->totalhigh = 0; - val->freehigh = 0; - - val->mem_unit = PAGE_SIZE; -} diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in --- a/arch/x86_64/config.in Sun May 5 20:39:49 2002 +++ b/arch/x86_64/config.in Sun May 5 20:39:49 2002 @@ -199,9 +199,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c --- a/arch/x86_64/mm/init.c Sun May 5 20:39:49 2002 +++ b/arch/x86_64/mm/init.c Sun May 5 20:39:49 2002 @@ -39,8 +39,6 @@ mmu_gather_t mmu_gathers[NR_CPUS]; -static unsigned long totalram_pages; - /* * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the * physical space so we can cache the place of the first one and move @@ -125,7 +123,7 @@ pte = pte_offset_kernel(pmd, vaddr); if (pte_val(*pte)) pte_ERROR(*pte); - set_pte(pte, mk_pte_phys(phys, prot)); + set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); /* * It's enough to flush this one mapping. @@ -385,15 +383,3 @@ } } #endif - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = 0; - val->freeram = nr_free_pages(); - val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; - return; -} diff -Nru a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c --- a/arch/x86_64/mm/ioremap.c Sun May 5 20:39:49 2002 +++ b/arch/x86_64/mm/ioremap.c Sun May 5 20:39:49 2002 @@ -20,6 +20,7 @@ unsigned long phys_addr, unsigned long flags) { unsigned long end; + unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -27,15 +28,16 @@ end = PMD_SIZE; if (address >= end) BUG(); + pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | + set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_GLOBAL | _PAGE_DIRTY | _PAGE_ACCESSED | flags))); address += PAGE_SIZE; - phys_addr += PAGE_SIZE; + pfn++; pte++; } while (address && (address < end)); } diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Sun May 5 20:39:49 2002 +++ b/drivers/block/ll_rw_blk.c Sun May 5 20:39:49 2002 @@ -1598,10 +1598,12 @@ BUG_ON(!bh->b_end_io); if ((rw == READ || rw == READA) && buffer_uptodate(bh)) - printk("%s: read of uptodate buffer\n", __FUNCTION__); + buffer_error(); if (rw == WRITE && !buffer_uptodate(bh)) - printk("%s: write of non-uptodate buffer\n", __FUNCTION__); - + buffer_error(); + if (rw == READ && buffer_dirty(bh)) + buffer_error(); + set_buffer_req(bh); /* diff -Nru a/drivers/bluetooth/Config.help b/drivers/bluetooth/Config.help --- a/drivers/bluetooth/Config.help Sun May 5 20:39:49 2002 +++ b/drivers/bluetooth/Config.help Sun May 5 20:39:49 2002 @@ -1,11 +1,23 @@ +HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with - serial port interface. + serial port interface. You will also need this driver if you have + UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card + adapter and BrainBoxes Bluetooth PC Card. Say Y here to compile support for Bluetooth UART devices into the kernel or say M to compile it as module (hci_uart.o). +HCI UART (H4) protocol support +CONFIG_BLUEZ_HCIUART_H4 + UART (H4) is serial protocol for communication between Bluetooth + device and host. This protocol is required for most UART based + Bluetooth device (including PCMCIA and CF). + + Say Y here to compile support for HCI UART (H4) protocol. + +HCI USB driver CONFIG_BLUEZ_HCIUSB Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with @@ -14,6 +26,24 @@ Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (hci_usb.o). +HCI USB firmware download support +CONFIG_BLUEZ_USB_FW_LOAD + Firmware download support for Bluetooth USB devices. + This support is required for devices like Broadcom BCM2033. + + HCI USB driver uses external firmware downloader program provided + in BlueFW package. + For more information, see . + +HCI USB zero packet support +CONFIG_BLUEZ_USB_ZERO_PACKET + Support for USB zero packets. + This option is provided only as a work around for buggy Bluetooth USB + devices. Do _not_ enable it unless you know for sure that your device + requires zero packets. + Most people should say N here. + +HCI VHCI Virtual HCI device driver CONFIG_BLUEZ_HCIVHCI Bluetooth Virtual HCI device driver. This driver is required if you want to use HCI Emulation software. @@ -21,3 +51,24 @@ Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci.o). +HCI DTL1 (PC Card) device driver +CONFIG_BLUEZ_HCIDTL1 + Bluetooth HCI DTL1 (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + Nokia DTL1 interface: + Nokia Bluetooth Card + Socket Bluetooth CF Card + + Say Y here to compile support for HCI DTL1 devices into the + kernel or say M to compile it as module (dtl1_cs.o). + +HCI BlueCard (PC Card) device driver +CONFIG_BLUEZ_HCIBLUECARD + Bluetooth HCI BlueCard (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + Anycom BlueCard interface: + Anycom Bluetooth PC Card + Anycom Bluetooth CF Card + + Say Y here to compile support for HCI BlueCard devices into the + kernel or say M to compile it as module (bluecard_cs.o). diff -Nru a/drivers/bluetooth/Config.in b/drivers/bluetooth/Config.in --- a/drivers/bluetooth/Config.in Sun May 5 20:39:50 2002 +++ b/drivers/bluetooth/Config.in Sun May 5 20:39:50 2002 @@ -2,7 +2,20 @@ comment 'Bluetooth device drivers' dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB +if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then + bool ' Firmware download support' CONFIG_BLUEZ_USB_FW_LOAD + bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET +fi + dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ -dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ +if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then + bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 +fi + +dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ + +dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ + +dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ endmenu diff -Nru a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile --- a/drivers/bluetooth/Makefile Sun May 5 20:39:49 2002 +++ b/drivers/bluetooth/Makefile Sun May 5 20:39:49 2002 @@ -4,8 +4,19 @@ O_TARGET := bluetooth.o +list-multi := hci_uart.o + obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o -obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o +obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o +uart-y := hci_ldisc.o +uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o + +obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o +obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o + include $(TOPDIR)/Rules.make + +hci_uart.o: $(uart-y) + $(LD) -r -o $@ $(uart-y) diff -Nru a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/bluecard_cs.c Sun May 5 20:39:50 2002 @@ -0,0 +1,1124 @@ +/* + * + * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0x86bc; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct bluecard_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + struct timer_list timer; /* For LED control */ + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + + unsigned char ctrl_reg; + unsigned long hw_state; /* Status of the hardware and LED control */ +} bluecard_info_t; + + +void bluecard_config(dev_link_t * link); +void bluecard_release(u_long arg); +int bluecard_event(event_t event, int priority, event_callback_args_t * args); + +static dev_info_t dev_info = "bluecard_cs"; + +dev_link_t *bluecard_attach(void); +void bluecard_detach(dev_link_t *); + +dev_link_t *dev_list = NULL; + + +/* Default baud rate: 57600, 115200, 230400 or 460800 */ +#define DEFAULT_BAUD_RATE 230400 + + +/* Hardware states */ +#define CARD_READY 1 +#define CARD_HAS_PCCARD_ID 4 +#define CARD_HAS_POWER_LED 5 +#define CARD_HAS_ACTIVITY_LED 6 + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ +#define XMIT_BUF_ONE_READY 6 +#define XMIT_BUF_TWO_READY 7 +#define XMIT_SENDING_READY 8 + +/* Receiver states */ +#define RECV_WAIT_PACKET_TYPE 0 +#define RECV_WAIT_EVENT_HEADER 1 +#define RECV_WAIT_ACL_HEADER 2 +#define RECV_WAIT_SCO_HEADER 3 +#define RECV_WAIT_DATA 4 + +/* Special packet types */ +#define PKT_BAUD_RATE_57600 0x80 +#define PKT_BAUD_RATE_115200 0x81 +#define PKT_BAUD_RATE_230400 0x82 +#define PKT_BAUD_RATE_460800 0x83 + + +/* These are the register offsets */ +#define REG_COMMAND 0x20 +#define REG_INTERRUPT 0x21 +#define REG_CONTROL 0x22 +#define REG_RX_CONTROL 0x24 +#define REG_CARD_RESET 0x30 +#define REG_LED_CTRL 0x30 + +/* REG_COMMAND */ +#define REG_COMMAND_TX_BUF_ONE 0x01 +#define REG_COMMAND_TX_BUF_TWO 0x02 +#define REG_COMMAND_RX_BUF_ONE 0x04 +#define REG_COMMAND_RX_BUF_TWO 0x08 +#define REG_COMMAND_RX_WIN_ONE 0x00 +#define REG_COMMAND_RX_WIN_TWO 0x10 + +/* REG_CONTROL */ +#define REG_CONTROL_BAUD_RATE_57600 0x00 +#define REG_CONTROL_BAUD_RATE_115200 0x01 +#define REG_CONTROL_BAUD_RATE_230400 0x02 +#define REG_CONTROL_BAUD_RATE_460800 0x03 +#define REG_CONTROL_RTS 0x04 +#define REG_CONTROL_BT_ON 0x08 +#define REG_CONTROL_BT_RESET 0x10 +#define REG_CONTROL_BT_RES_PU 0x20 +#define REG_CONTROL_INTERRUPT 0x40 +#define REG_CONTROL_CARD_RESET 0x80 + +/* REG_RX_CONTROL */ +#define RTS_LEVEL_SHIFT_BITS 0x02 + + + +/* ======================== LED handling routines ======================== */ + + +void bluecard_activity_led_timeout(u_long arg) +{ + bluecard_info_t *info = (bluecard_info_t *) arg; + unsigned int iobase = info->link.io.BasePort1; + + if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { + /* Disable activity LED */ + outb(0x08 | 0x20, iobase + 0x30); + } else { + /* Disable power LED */ + outb(0x00, iobase + 0x30); + } +} + + +static void bluecard_enable_activity_led(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + + if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { + /* Enable activity LED */ + outb(0x10 | 0x40, iobase + 0x30); + + /* Stop the LED after HZ/4 */ + mod_timer(&(info->timer), jiffies + HZ / 4); + } else { + /* Enable power LED */ + outb(0x08 | 0x20, iobase + 0x30); + + /* Stop the LED after HZ/2 */ + mod_timer(&(info->timer), jiffies + HZ / 2); + } +} + + + +/* ======================== Interrupt handling ======================== */ + + +static int bluecard_write(unsigned int iobase, unsigned int offset, + __u8 * buf, int len) +{ + int i, actual; + + actual = (len > 15) ? 15 : len; + + outb_p(actual, iobase + offset); + + for (i = 0; i < actual; i++) + outb_p(buf[i], iobase + offset + i + 1); + + return actual; +} + + +static void bluecard_write_wakeup(bluecard_info_t * info) +{ + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) + return; + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + do { + register unsigned int iobase = info->link.io.BasePort1; + register unsigned int offset; + register unsigned char command; + register unsigned long ready_bit; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { + if (!test_bit + (XMIT_BUF_TWO_READY, &(info->tx_state))) + break; + offset = 0x10; + command = REG_COMMAND_TX_BUF_TWO; + ready_bit = XMIT_BUF_TWO_READY; + } else { + if (!test_bit + (XMIT_BUF_ONE_READY, &(info->tx_state))) + break; + offset = 0x00; + command = REG_COMMAND_TX_BUF_ONE; + ready_bit = XMIT_BUF_ONE_READY; + } + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + if (skb->pkt_type & 0x80) { + + /* Disable RTS */ + info->ctrl_reg |= REG_CONTROL_RTS; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + } + + /* Activate LED */ + bluecard_enable_activity_led(info); + + /* Send frame */ + len = bluecard_write(iobase, offset, skb->data, skb->len); + + /* Tell the FPGA to send the data */ + outb_p(command, iobase + REG_COMMAND); + + /* Mark the buffer as dirty */ + clear_bit(ready_bit, &(info->tx_state)); + + if (skb->pkt_type & 0x80) { + + wait_queue_head_t wait; + unsigned char baud_reg; + + switch (skb->pkt_type) { + case PKT_BAUD_RATE_460800: + baud_reg = REG_CONTROL_BAUD_RATE_460800; + break; + case PKT_BAUD_RATE_230400: + baud_reg = REG_CONTROL_BAUD_RATE_230400; + break; + case PKT_BAUD_RATE_115200: + baud_reg = REG_CONTROL_BAUD_RATE_115200; + break; + case PKT_BAUD_RATE_57600: + /* Fall through... */ + default: + baud_reg = REG_CONTROL_BAUD_RATE_57600; + break; + } + + /* Wait until the command reaches the baseband */ + init_waitqueue_head(&wait); + interruptible_sleep_on_timeout(&wait, HZ / 10); + + /* Set baud on baseband */ + info->ctrl_reg &= ~0x03; + info->ctrl_reg |= baud_reg; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Enable RTS */ + info->ctrl_reg &= ~REG_CONTROL_RTS; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Wait before the next HCI packet can be send */ + interruptible_sleep_on_timeout(&wait, HZ); + + } + + if (len == skb->len) { + kfree_skb(skb); + } else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + /* Change buffer */ + change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + clear_bit(XMIT_SENDING, &(info->tx_state)); +} + + +static int bluecard_read(unsigned int iobase, unsigned int offset, + __u8 * buf, int size) +{ + int i, n, len; + + outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); + + len = inb(iobase + offset); + n = 0; + i = 1; + + while (n < len) { + + if (i == 16) { + outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); + i = 0; + } + + buf[n] = inb(iobase + offset + i); + + n++; + i++; + + } + + return len; +} + + +static void bluecard_receive(bluecard_info_t * info, unsigned int offset) +{ + unsigned int iobase; + unsigned char buf[31]; + int i, len; + + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) + bluecard_enable_activity_led(info); + + len = bluecard_read(iobase, offset, buf, sizeof(buf)); + + for (i = 0; i < len; i++) { + + /* Allocate packet */ + if (info->rx_skb == NULL) { + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); + return; + } + } + + if (info->rx_state == RECV_WAIT_PACKET_TYPE) { + + info->rx_skb->dev = (void *) &(info->hdev); + info->rx_skb->pkt_type = buf[i]; + + switch (info->rx_skb->pkt_type) { + + case 0x00: + /* init packet */ + if (offset != 0x00) { + set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); + set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); + set_bit(XMIT_SENDING_READY, &(info->tx_state)); + bluecard_write_wakeup(info); + } + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + case HCI_EVENT_PKT: + info->rx_state = RECV_WAIT_EVENT_HEADER; + info->rx_count = HCI_EVENT_HDR_SIZE; + break; + + case HCI_ACLDATA_PKT: + info->rx_state = RECV_WAIT_ACL_HEADER; + info->rx_count = HCI_ACL_HDR_SIZE; + break; + + case HCI_SCODATA_PKT: + info->rx_state = RECV_WAIT_SCO_HEADER; + info->rx_count = HCI_SCO_HDR_SIZE; + break; + + default: + /* unknown packet */ + printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + info->hdev.stat.err_rx++; + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } else { + + *skb_put(info->rx_skb, 1) = buf[i]; + info->rx_count--; + + if (info->rx_count == 0) { + + int dlen; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + + switch (info->rx_state) { + + case RECV_WAIT_EVENT_HEADER: + eh = (hci_event_hdr *) (info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = eh->plen; + break; + + case RECV_WAIT_ACL_HEADER: + ah = (hci_acl_hdr *) (info->rx_skb->data); + dlen = __le16_to_cpu(ah->dlen); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = dlen; + break; + + case RECV_WAIT_SCO_HEADER: + sh = (hci_sco_hdr *) (info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = sh->dlen; + break; + + case RECV_WAIT_DATA: + hci_recv_frame(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } + + } + + + } + + info->hdev.stat.byte_rx += len; +} + + +void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +{ + bluecard_info_t *info = dev_inst; + unsigned int iobase; + unsigned char reg; + + if (!info) { + printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + if (!test_bit(CARD_READY, &(info->hw_state))) + return; + + iobase = info->link.io.BasePort1; + + spin_lock(&(info->lock)); + + /* Disable interrupt */ + info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + reg = inb(iobase + REG_INTERRUPT); + + if ((reg != 0x00) && (reg != 0xff)) { + + if (reg & 0x04) { + bluecard_receive(info, 0x00); + outb(0x04, iobase + REG_INTERRUPT); + outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); + } + + if (reg & 0x08) { + bluecard_receive(info, 0x10); + outb(0x08, iobase + REG_INTERRUPT); + outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); + } + + if (reg & 0x01) { + set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); + outb(0x01, iobase + REG_INTERRUPT); + bluecard_write_wakeup(info); + } + + if (reg & 0x02) { + set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); + outb(0x02, iobase + REG_INTERRUPT); + bluecard_write_wakeup(info); + } + + } + + /* Enable interrupt */ + info->ctrl_reg |= REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + spin_unlock(&(info->lock)); +} + + + +/* ======================== Device specific HCI commands ======================== */ + + +static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + struct sk_buff *skb; + int i; + + /* Ericsson baud rate command */ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; + + if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); + return -1; + } + + switch (baud) { + case 460800: + cmd[4] = 0x00; + skb->pkt_type = PKT_BAUD_RATE_460800; + break; + case 230400: + cmd[4] = 0x01; + skb->pkt_type = PKT_BAUD_RATE_230400; + break; + case 115200: + cmd[4] = 0x02; + skb->pkt_type = PKT_BAUD_RATE_115200; + break; + case 57600: + /* Fall through... */ + default: + cmd[4] = 0x03; + skb->pkt_type = PKT_BAUD_RATE_57600; + break; + } + + for (i = 0; i < sizeof(cmd); i++) + *skb_put(skb, 1) = cmd[i]; + + skb_queue_tail(&(info->txq), skb); + + bluecard_write_wakeup(info); + + return 0; +} + + + +/* ======================== HCI interface ======================== */ + + +static int bluecard_hci_flush(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + return 0; +} + + +static int bluecard_hci_open(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + unsigned int iobase = info->link.io.BasePort1; + + bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); + + if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + /* Enable LED */ + outb(0x08 | 0x20, iobase + 0x30); + + return 0; +} + + +static int bluecard_hci_close(struct hci_dev *hdev) +{ + bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + unsigned int iobase = info->link.io.BasePort1; + + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + bluecard_hci_flush(hdev); + + /* Disable LED */ + outb(0x00, iobase + 0x30); + + return 0; +} + + +static int bluecard_hci_send_frame(struct sk_buff *skb) +{ + bluecard_info_t *info; + struct hci_dev *hdev = (struct hci_dev *) (skb->dev); + + if (!hdev) { + printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (bluecard_info_t *) (hdev->driver_data); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + }; + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); + skb_queue_tail(&(info->txq), skb); + + bluecard_write_wakeup(info); + + return 0; +} + + +static void bluecard_hci_destruct(struct hci_dev *hdev) +{ +} + + +static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, + unsigned long arg) +{ + return -ENOIOCTLCMD; +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int bluecard_open(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + unsigned char id; + + spin_lock_init(&(info->lock)); + + init_timer(&(info->timer)); + info->timer.function = &bluecard_activity_led_timeout; + info->timer.data = (u_long) info; + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + info->rx_skb = NULL; + + id = inb(iobase + 0x30); + + if ((id & 0x0f) == 0x02) + set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); + + if (id & 0x10) + set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); + + if (id & 0x20) + set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); + + /* Reset card */ + info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Turn FPGA off */ + outb(0x80, iobase + 0x30); + + /* Wait some time */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 100); + + /* Turn FPGA on */ + outb(0x00, iobase + 0x30); + + /* Activate card */ + info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Enable interrupt */ + outb(0xff, iobase + REG_INTERRUPT); + info->ctrl_reg |= REG_CONTROL_INTERRUPT; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Start the RX buffers */ + outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); + outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); + + /* Signal that the hardware is ready */ + set_bit(CARD_READY, &(info->hw_state)); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + /* Control the point at which RTS is enabled */ + outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((HZ * 5) / 4); // or set it to 3/2 + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = bluecard_hci_open; + hdev->close = bluecard_hci_close; + hdev->flush = bluecard_hci_flush; + hdev->send = bluecard_hci_send_frame; + hdev->destruct = bluecard_hci_destruct; + hdev->ioctl = bluecard_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + return 0; +} + + +int bluecard_close(bluecard_info_t * info) +{ + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + bluecard_hci_close(hdev); + + clear_bit(CARD_READY, &(info->hw_state)); + + /* Reset card */ + info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; + outb(info->ctrl_reg, iobase + REG_CONTROL); + + /* Turn FPGA off */ + outb(0x80, iobase + 0x30); + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name); + + return 0; +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + + CardServices(ReportError, handle, &err); +} + + +dev_link_t *bluecard_attach(void) +{ + bluecard_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + link = &info->link; + link->priv = info; + + link->release.function = &bluecard_release; + link->release.data = (u_long) link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = bluecard_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &bluecard_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + bluecard_detach(link); + return NULL; + } + + return link; +} + + +void bluecard_detach(dev_link_t * link) +{ + bluecard_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + bluecard_release((u_long) link); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); +} + + +static int get_tuple(int fn, client_handle_t handle, tuple_t * tuple, + cisparse_t * parse) +{ + int i; + + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + + return CardServices(ParseTuple, handle, tuple, parse); +} + + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +void bluecard_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + bluecard_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + config_info_t config; + int i, n, last_ret, last_fn; + + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + link->conf.ConfigIndex = 0x20; + link->io.NumPorts1 = 64; + link->io.IOAddrLines = 6; + + for (n = 0; n < 0x400; n += 0x40) { + link->io.BasePort1 = n ^ 0x300; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + + MOD_INC_USE_COUNT; + + if (bluecard_open(info) != 0) + goto failed; + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + +failed: + bluecard_release((u_long) link); +} + + +void bluecard_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + bluecard_info_t *info = link->priv; + + if (link->state & DEV_PRESENT) + bluecard_close(info); + + MOD_DEC_USE_COUNT; + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; +} + + +int bluecard_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + bluecard_info_t *info = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + bluecard_close(info); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + bluecard_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, + &link->conf); + break; + } + + return 0; +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_bluecard_cs(void) +{ + servinfo_t serv; + int err; + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n"); + return -1; + } + + err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach); + + return err; +} + + +void __exit exit_bluecard_cs(void) +{ + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + bluecard_detach(dev_list); +} + + +module_init(init_bluecard_cs); +module_exit(exit_bluecard_cs); + +EXPORT_NO_SYMBOLS; diff -Nru a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/dtl1_cs.c Sun May 5 20:39:50 2002 @@ -0,0 +1,939 @@ +/* + * + * A driver for Nokia Connectivity Card DTL-1 devices + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct dtl1_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + + unsigned long flowmask; /* HCI flow mask */ + int ri_latch; + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + +} dtl1_info_t; + + +void dtl1_config(dev_link_t *link); +void dtl1_release(u_long arg); +int dtl1_event(event_t event, int priority, event_callback_args_t *args); + +static dev_info_t dev_info = "dtl1_cs"; + +dev_link_t *dtl1_attach(void); +void dtl1_detach(dev_link_t *); + +dev_link_t *dev_list = NULL; + + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_WAITING 8 + +/* Receiver States */ +#define RECV_WAIT_NSH 0 +#define RECV_WAIT_DATA 1 + + +typedef struct { + u8 type; + u8 zero; + u16 len; +} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ + +#define NSHL 4 /* Nokia Specific Header Length */ + + + +/* ======================== Interrupt handling ======================== */ + + +static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) { + + int actual = 0; + + + /* Tx FIFO should be empty */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) + return 0; + + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } + + + return actual; + +} + + +static void dtl1_write_wakeup(dtl1_info_t *info) { + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + + if (test_bit(XMIT_WAITING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + + /* Send frame */ + len = dtl1_write(iobase, 32, skb->data, skb->len); + + if (len == skb->len) { + set_bit(XMIT_WAITING, &(info->tx_state)); + kfree_skb(skb); + } + else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + + clear_bit(XMIT_SENDING, &(info->tx_state)); + +} + + +static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) { + + u8 flowmask = *(u8 *)skb->data; + int i; + + + printk(KERN_INFO "dtl1_cs: Nokia control data = "); + for (i = 0; i < skb->len; i++) { + printk("%02x ", skb->data[i]); + } + printk("\n"); + + + /* transition to active state */ + if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + info->flowmask = flowmask; + + + kfree_skb(skb); + +} + + +static void dtl1_receive(dtl1_info_t *info) { + + unsigned int iobase; + nsh_t *nsh; + int boguscount = 0; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); + return; + } + + + iobase = info->link.io.BasePort1; + + do { + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + return; + } + + + *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + nsh = (nsh_t *)info->rx_skb->data; + + info->rx_count--; + + + if (info->rx_count == 0) { + + switch (info->rx_state) { + case RECV_WAIT_NSH: + info->rx_state = RECV_WAIT_DATA; + info->rx_count = nsh->len + (nsh->len & 0x0001); + break; + case RECV_WAIT_DATA: + info->rx_skb->pkt_type = nsh->type; + + /* remove PAD byte if it exists */ + if (nsh->len & 0x0001) { + info->rx_skb->tail--; + info->rx_skb->len--; + } + + /* remove NSH */ + skb_pull(info->rx_skb, NSHL); + + + switch (info->rx_skb->pkt_type) { + case 0x80: + /* control data for the Nokia Card */ + dtl1_control(info, info->rx_skb); + break; + case 0x82: + case 0x83: + case 0x84: + /* send frame to the HCI layer */ + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type &= 0x0f; + hci_recv_frame(info->rx_skb); + break; + default: + /* unknown packet */ + printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + kfree_skb(info->rx_skb); + break; + } + + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + break; + } + + } + + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) + break; + + } while (inb(iobase + UART_LSR) & UART_LSR_DR); + + +} + + +void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { + + dtl1_info_t *info = dev_inst; + unsigned int iobase; + unsigned char msr; + int boguscount = 0; + int iir, lsr; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + + iobase = info->link.io.BasePort1; + + + spin_lock(&(info->lock)); + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + switch (iir) { + case UART_IIR_RLSI: + printk(KERN_NOTICE "dtl1_cs: RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + dtl1_receive(info); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) { + /* Transmitter ready for data */ + dtl1_write_wakeup(info); + } + break; + default: + printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + + } + + + msr = inb(iobase + UART_MSR); + + if (info->ri_latch ^ (msr & UART_MSR_RI)) { + info->ri_latch = msr & UART_MSR_RI; + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + spin_unlock(&(info->lock)); + +} + + + +/* ======================== HCI interface ======================== */ + + +static int dtl1_hci_open(struct hci_dev *hdev) { + + set_bit(HCI_RUNNING, &(hdev->flags)); + + + return 0; + +} + + +static int dtl1_hci_flush(struct hci_dev *hdev) { + + dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); + + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + + return 0; + +} + + +static int dtl1_hci_close(struct hci_dev *hdev) { + + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + + dtl1_hci_flush(hdev); + + + return 0; + +} + + +static int dtl1_hci_send_frame(struct sk_buff *skb) { + + dtl1_info_t *info; + struct hci_dev* hdev = (struct hci_dev *)(skb->dev); + struct sk_buff *s; + nsh_t nsh; + + + if (!hdev) { + printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (dtl1_info_t *)(hdev->driver_data); + + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + nsh.type = 0x81; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + nsh.type = 0x82; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + nsh.type = 0x83; + break; + }; + + nsh.zero = 0; + nsh.len = skb->len; + + s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); + skb_reserve(s, NSHL); + memcpy(skb_put(s, skb->len), skb->data, skb->len); + if (skb->len & 0x0001) + *skb_put(s, 1) = 0; /* PAD */ + + /* Prepend skb with Nokia frame header and queue */ + memcpy(skb_push(s, NSHL), &nsh, NSHL); + skb_queue_tail(&(info->txq), s); + + + dtl1_write_wakeup(info); + + kfree_skb(skb); + + + return 0; + +} + + +static void dtl1_hci_destruct(struct hci_dev *hdev) { +} + + +static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { + + return -ENOIOCTLCMD; + +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int dtl1_open(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + + + spin_lock_init(&(info->lock)); + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + + set_bit(XMIT_WAITING, &(info->tx_state)); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); + + info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; + + /* Turn on interrupts */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 2); + + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = dtl1_hci_open; + hdev->close = dtl1_hci_close; + hdev->flush = dtl1_hci_flush; + hdev->send = dtl1_hci_send_frame; + hdev->destruct = dtl1_hci_destruct; + hdev->ioctl = dtl1_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + + return 0; + +} + + +int dtl1_close(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + + dtl1_hci_close(hdev); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); + + + return 0; + +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) { + + error_info_t err = { func, ret }; + + + CardServices(ReportError, handle, &err); + +} + + +dev_link_t *dtl1_attach(void) { + + dtl1_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + + link = &info->link; + link->priv = info; + + link->release.function = &dtl1_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = dtl1_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &dtl1_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dtl1_detach(link); + return NULL; + } + + + return link; + +} + + +void dtl1_detach(dev_link_t *link) { + + dtl1_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + dtl1_release((u_long)link); + + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); + +} + + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) { + + int i; + + + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + + return CardServices(ParseTuple, handle, tuple, parse); + +} + + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +void dtl1_config(dev_link_t *link) { + + client_handle_t handle = link->handle; + dtl1_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, last_ret, last_fn; + + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + /* Look for a generic full-sized window */ + link->io.NumPorts1 = 8; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; /*yo*/ + link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + + MOD_INC_USE_COUNT; + + if (dtl1_open(info) != 0) + goto failed; + + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + + return; + + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + dtl1_release((u_long)link); + +} + + +void dtl1_release(u_long arg) { + + dev_link_t *link = (dev_link_t *)arg; + dtl1_info_t *info = link->priv; + + + if (link->state & DEV_PRESENT) + dtl1_close(info); + + MOD_DEC_USE_COUNT; + + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + +} + + +int dtl1_event(event_t event, int priority, event_callback_args_t *args) { + + dev_link_t *link = args->client_data; + dtl1_info_t *info = link->priv; + + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dtl1_close(info); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dtl1_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + + return 0; + +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_dtl1_cs(void) { + + servinfo_t serv; + int err; + + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); + return -1; + } + + + err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); + + + return err; + +} + +void __exit exit_dtl1_cs(void) { + + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + dtl1_detach(dev_list); + +} + + +module_init(init_dtl1_cs); +module_exit(exit_dtl1_cs); + +EXPORT_NO_SYMBOLS; diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_h4.c Sun May 5 20:39:50 2002 @@ -0,0 +1,273 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART(H4) protocol. + * + * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + */ +#define VERSION "1.1" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" +#include "hci_h4.h" + +#ifndef HCI_UART_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) +#endif + +/* Initialize protocol */ +static int h4_open(struct n_hci *n_hci) +{ + struct h4_struct *h4; + + BT_DBG("n_hci %p", n_hci); + + h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); + if (!h4) + return -ENOMEM; + memset(h4, 0, sizeof(*h4)); + + n_hci->priv = h4; + return 0; +} + +/* Flush protocol data */ +static int h4_flush(struct n_hci *n_hci) +{ + BT_DBG("n_hci %p", n_hci); + return 0; +} + +/* Close protocol */ +static int h4_close(struct n_hci *n_hci) +{ + struct h4_struct *h4 = n_hci->priv; + n_hci->priv = NULL; + + BT_DBG("n_hci %p", n_hci); + + if (h4->rx_skb) + kfree_skb(h4->rx_skb); + + kfree(h4); + return 0; +} + +/* Send data */ +static int h4_send(struct n_hci *n_hci, void *data, int len) +{ + struct tty_struct *tty = n_hci->tty; + + BT_DBG("n_hci %p len %d", n_hci, len); + + /* Send frame to TTY driver */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + return tty->driver.write(tty, 0, data, len); +} + +/* Init frame before queueing (padding, crc, etc) */ +static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb) +{ + BT_DBG("n_hci %p skb %p", n_hci, skb); + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &skb->pkt_type, 1); + return skb; +} + +static inline int h4_check_data_len(struct h4_struct *h4, int len) +{ + register int room = skb_tailroom(h4->rx_skb); + + BT_DBG("len %d room %d", len, room); + if (!len) { + BT_DMP(h4->rx_skb->data, h4->rx_skb->len); + hci_recv_frame(h4->rx_skb); + } else if (len > room) { + BT_ERR("Data length is to large"); + kfree_skb(h4->rx_skb); + } else { + h4->rx_state = H4_W4_DATA; + h4->rx_count = len; + return len; + } + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + h4->rx_count = 0; + return 0; +} + +/* Recv data */ +static int h4_recv(struct n_hci *n_hci, void *data, int count) +{ + struct h4_struct *h4 = n_hci->priv; + register char *ptr; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + register int len, type, dlen; + + BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count); + + ptr = data; + while (count) { + if (h4->rx_count) { + len = MIN(h4->rx_count, count); + memcpy(skb_put(h4->rx_skb, len), ptr, len); + h4->rx_count -= len; count -= len; ptr += len; + + if (h4->rx_count) + continue; + + switch (h4->rx_state) { + case H4_W4_DATA: + BT_DBG("Complete data"); + + BT_DMP(h4->rx_skb->data, h4->rx_skb->len); + + hci_recv_frame(h4->rx_skb); + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + continue; + + case H4_W4_EVENT_HDR: + eh = (hci_event_hdr *) h4->rx_skb->data; + + BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); + + h4_check_data_len(h4, eh->plen); + continue; + + case H4_W4_ACL_HDR: + ah = (hci_acl_hdr *) h4->rx_skb->data; + dlen = __le16_to_cpu(ah->dlen); + + BT_DBG("ACL header: dlen %d", dlen); + + h4_check_data_len(h4, dlen); + continue; + + case H4_W4_SCO_HDR: + sh = (hci_sco_hdr *) h4->rx_skb->data; + + BT_DBG("SCO header: dlen %d", sh->dlen); + + h4_check_data_len(h4, sh->dlen); + continue; + }; + } + + /* H4_W4_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + BT_DBG("Event packet"); + h4->rx_state = H4_W4_EVENT_HDR; + h4->rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + BT_DBG("ACL packet"); + h4->rx_state = H4_W4_ACL_HDR; + h4->rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + BT_DBG("SCO packet"); + h4->rx_state = H4_W4_SCO_HDR; + h4->rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); + n_hci->hdev.stat.err_rx++; + ptr++; count--; + continue; + }; + ptr++; count--; + + /* Allocate packet */ + h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!h4->rx_skb) { + BT_ERR("Can't allocate mem for new packet"); + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_count = 0; + return 0; + } + h4->rx_skb->dev = (void *) &n_hci->hdev; + h4->rx_skb->pkt_type = type; + } + return count; +} + +static struct hci_uart_proto h4p = { + id: HCI_UART_H4, + open: h4_open, + close: h4_close, + send: h4_send, + recv: h4_recv, + preq: h4_preq, + flush: h4_flush, +}; + +int h4_init(void) +{ + return hci_uart_register_proto(&h4p); +} + +int h4_deinit(void) +{ + return hci_uart_unregister_proto(&h4p); +} diff -Nru a/drivers/bluetooth/hci_h4.h b/drivers/bluetooth/hci_h4.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_h4.h Sun May 5 20:39:50 2002 @@ -0,0 +1,43 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifdef __KERNEL__ +struct h4_struct { + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; +}; + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE 0 +#define H4_W4_EVENT_HDR 1 +#define H4_W4_ACL_HDR 2 +#define H4_W4_SCO_HDR 3 +#define H4_W4_DATA 4 + +#endif /* __KERNEL__ */ diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_ldisc.c Sun May 5 20:39:50 2002 @@ -0,0 +1,554 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART driver. + * + * $Id: hci_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + */ +#define VERSION "2.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" + +#ifndef HCI_UART_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) +#endif + +static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; + +int hci_uart_register_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (hup[p->id]) + return -EEXIST; + + hup[p->id] = p; + return 0; +} + +int hci_uart_unregister_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (!hup[p->id]) + return -EINVAL; + + hup[p->id] = NULL; + return 0; +} + +static struct hci_uart_proto *n_hci_get_proto(unsigned int id) +{ + if (id >= HCI_UART_MAX_PROTO) + return NULL; + return hup[id]; +} + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +static int n_hci_open(struct hci_dev *hdev) +{ + BT_DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ + + set_bit(HCI_RUNNING, &hdev->flags); + return 0; +} + +/* Reset device */ +static int n_hci_flush(struct hci_dev *hdev) +{ + struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; + struct tty_struct *tty = n_hci->tty; + + BT_DBG("hdev %p tty %p", hdev, tty); + + /* Drop TX queue */ + skb_queue_purge(&n_hci->txq); + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (n_hci->proto->flush) + n_hci->proto->flush(n_hci); + + return 0; +} + +/* Close device */ +static int n_hci_close(struct hci_dev *hdev) +{ + BT_DBG("hdev %p", hdev); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + + n_hci_flush(hdev); + return 0; +} + +static int n_hci_tx_wakeup(struct n_hci *n_hci) +{ + struct hci_dev *hdev = &n_hci->hdev; + + if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) { + set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + return 0; + } + + BT_DBG(""); + do { + register struct sk_buff *skb; + register int len; + + clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + + if (!(skb = skb_dequeue(&n_hci->txq))) + break; + + len = n_hci->proto->send(n_hci, skb->data, skb->len); + n_hci->hdev.stat.byte_tx += len; + + if (len == skb->len) { + /* Complete frame was sent */ + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + }; + + kfree_skb(skb); + } else { + /* Subtract sent part and requeue */ + skb_pull(skb, len); + skb_queue_head(&n_hci->txq, skb); + } + } while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state)); + clear_bit(N_HCI_SENDING, &n_hci->tx_state); + return 0; +} + +/* Send frames from HCI layer */ +static int n_hci_send_frame(struct sk_buff *skb) +{ + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct tty_struct *tty; + struct n_hci *n_hci; + + if (!hdev) { + BT_ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + n_hci = (struct n_hci *) hdev->driver_data; + tty = n_hci->tty; + + BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); + + if (n_hci->proto->preq) { + skb = n_hci->proto->preq(n_hci, skb); + if (!skb) + return 0; + } + + skb_queue_tail(&n_hci->txq, skb); + n_hci_tx_wakeup(n_hci); + return 0; +} + +static void n_hci_destruct(struct hci_dev *hdev) +{ + struct n_hci *n_hci; + + if (!hdev) return; + + BT_DBG("%s", hdev->name); + + n_hci = (struct n_hci *) hdev->driver_data; + kfree(n_hci); + + MOD_DEC_USE_COUNT; +} + +/* ------ LDISC part ------ */ +/* n_hci_tty_open + * + * Called when line discipline changed to N_HCI. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static int n_hci_tty_open(struct tty_struct *tty) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + BT_DBG("tty %p", tty); + + if (n_hci) + return -EEXIST; + + if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + BT_ERR("Can't allocate controll structure"); + return -ENFILE; + } + memset(n_hci, 0, sizeof(struct n_hci)); + + tty->disc_data = n_hci; + n_hci->tty = tty; + + spin_lock_init(&n_hci->rx_lock); + skb_queue_head_init(&n_hci->txq); + + /* Flush any pending characters in the driver and line discipline */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + MOD_INC_USE_COUNT; + return 0; +} + +/* n_hci_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void n_hci_tty_close(struct tty_struct *tty) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + BT_DBG("tty %p", tty); + + /* Detach from the tty */ + tty->disc_data = NULL; + + if (n_hci) { + struct hci_dev *hdev = &n_hci->hdev; + n_hci_close(hdev); + + if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + n_hci->proto->close(n_hci); + hci_unregister_dev(hdev); + } + + MOD_DEC_USE_COUNT; + } +} + +/* n_hci_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void n_hci_tty_wakeup( struct tty_struct *tty ) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + BT_DBG(""); + + if (!n_hci) + return; + + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + if (tty != n_hci->tty) + return; + + n_hci_tx_wakeup(n_hci); +} + +/* n_hci_tty_room() + * + * Callback function from tty driver. Return the amount of + * space left in the receiver's buffer to decide if remote + * transmitter is to be throttled. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: number of bytes left in receive buffer + */ +static int n_hci_tty_room (struct tty_struct *tty) +{ + return 65536; +} + +/* n_hci_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + if (!n_hci || tty != n_hci->tty) + return; + + if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return; + + spin_lock(&n_hci->rx_lock); + n_hci->proto->recv(n_hci, (void *) data, count); + n_hci->hdev.stat.byte_rx += count; + spin_unlock(&n_hci->rx_lock); + + if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) + tty->driver.unthrottle(tty); +} + +static int n_hci_register_dev(struct n_hci *n_hci) +{ + struct hci_dev *hdev; + + BT_DBG(""); + + /* Initialize and register HCI device */ + hdev = &n_hci->hdev; + + hdev->type = HCI_UART; + hdev->driver_data = n_hci; + + hdev->open = n_hci_open; + hdev->close = n_hci_close; + hdev->flush = n_hci_flush; + hdev->send = n_hci_send_frame; + hdev->destruct = n_hci_destruct; + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device %s", hdev->name); + return -ENODEV; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int n_hci_set_proto(struct n_hci *n_hci, int id) +{ + struct hci_uart_proto *p; + int err; + + p = n_hci_get_proto(id); + if (!p) + return -EPROTONOSUPPORT; + + err = p->open(n_hci); + if (err) + return err; + + n_hci->proto = p; + + err = n_hci_register_dev(n_hci); + if (err) { + p->close(n_hci); + return err; + } + return 0; +} + +/* n_hci_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + int err = 0; + + BT_DBG(""); + + /* Verify the status of the device */ + if (!n_hci) + return -EBADF; + + switch (cmd) { + case HCIUARTSETPROTO: + if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + err = n_hci_set_proto(n_hci, arg); + if (err) { + clear_bit(N_HCI_PROTO_SET, &n_hci->flags); + return err; + } + tty->low_latency = 1; + } else + return -EBUSY; + + case HCIUARTGETPROTO: + if (test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return n_hci->proto->id; + return -EUNATCH; + + default: + err = n_tty_ioctl(tty, file, cmd, arg); + break; + }; + + return err; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +{ + return 0; +} +static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +{ + return 0; +} +static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +{ + return 0; +} + +#ifdef CONFIG_BLUEZ_HCIUART_H4 +int h4_init(void); +int h4_deinit(void); +#endif + +int __init n_hci_init(void) +{ + static struct tty_ldisc n_hci_ldisc; + int err; + + BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + + /* Register the tty discipline */ + + memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); + n_hci_ldisc.magic = TTY_LDISC_MAGIC; + n_hci_ldisc.name = "n_hci"; + n_hci_ldisc.open = n_hci_tty_open; + n_hci_ldisc.close = n_hci_tty_close; + n_hci_ldisc.read = n_hci_tty_read; + n_hci_ldisc.write = n_hci_tty_write; + n_hci_ldisc.ioctl = n_hci_tty_ioctl; + n_hci_ldisc.poll = n_hci_tty_poll; + n_hci_ldisc.receive_room= n_hci_tty_room; + n_hci_ldisc.receive_buf = n_hci_tty_receive; + n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; + + if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { + BT_ERR("Can't register HCI line discipline (%d)", err); + return err; + } + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_init(); +#endif + + return 0; +} + +void n_hci_cleanup(void) +{ + int err; + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_deinit(); +#endif + + /* Release tty registration of line discipline */ + if ((err = tty_register_ldisc(N_HCI, NULL))) + BT_ERR("Can't unregister HCI line discipline (%d)", err); +} + +module_init(n_hci_init); +module_exit(n_hci_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/bluetooth/hci_uart.c b/drivers/bluetooth/hci_uart.c --- a/drivers/bluetooth/hci_uart.c Sun May 5 20:39:50 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,580 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * BlueZ HCI UART driver. - * - * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ - */ -#define VERSION "1.0" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifndef HCI_UART_DEBUG -#undef DBG -#define DBG( A... ) -#undef DMP -#define DMP( A... ) -#endif - -/* ------- Interface to HCI layer ------ */ -/* Initialize device */ -int n_hci_open(struct hci_dev *hdev) -{ - DBG("%s %p", hdev->name, hdev); - - /* Nothing to do for UART driver */ - - hdev->flags |= HCI_RUNNING; - - return 0; -} - -/* Reset device */ -int n_hci_flush(struct hci_dev *hdev) -{ - struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; - struct tty_struct *tty = n_hci->tty; - - DBG("hdev %p tty %p", hdev, tty); - - /* Drop TX queue */ - skb_queue_purge(&n_hci->txq); - - /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - - return 0; -} - -/* Close device */ -int n_hci_close(struct hci_dev *hdev) -{ - DBG("hdev %p", hdev); - - hdev->flags &= ~HCI_RUNNING; - - n_hci_flush(hdev); - - return 0; -} - -int n_hci_tx_wakeup(struct n_hci *n_hci) -{ - register struct tty_struct *tty = n_hci->tty; - - if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { - set_bit(TRANS_WAKEUP, &n_hci->tx_state); - return 0; - } - - DBG(""); - do { - register struct sk_buff *skb; - register int len; - - clear_bit(TRANS_WAKEUP, &n_hci->tx_state); - - if (!(skb = skb_dequeue(&n_hci->txq))) - break; - - DMP(skb->data, skb->len); - - /* Send frame to TTY driver */ - tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - len = tty->driver.write(tty, 0, skb->data, skb->len); - - n_hci->hdev.stat.byte_tx += len; - - DBG("sent %d", len); - - if (len == skb->len) { - /* Full frame was sent */ - kfree_skb(skb); - } else { - /* Subtract sent part and requeue */ - skb_pull(skb, len); - skb_queue_head(&n_hci->txq, skb); - } - } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); - clear_bit(TRANS_SENDING, &n_hci->tx_state); - - return 0; -} - -/* Send frames from HCI layer */ -int n_hci_send_frame(struct sk_buff *skb) -{ - struct hci_dev* hdev = (struct hci_dev *) skb->dev; - struct tty_struct *tty; - struct n_hci *n_hci; - - if (!hdev) { - ERR("Frame for uknown device (hdev=NULL)"); - return -ENODEV; - } - - if (!(hdev->flags & HCI_RUNNING)) - return -EBUSY; - - n_hci = (struct n_hci *) hdev->driver_data; - tty = n_hci2tty(n_hci); - - DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); - - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - hdev->stat.cmd_tx++; - break; - }; - - /* Prepend skb with frame type and queue */ - memcpy(skb_push(skb, 1), &skb->pkt_type, 1); - skb_queue_tail(&n_hci->txq, skb); - - n_hci_tx_wakeup(n_hci); - - return 0; -} - -/* ------ LDISC part ------ */ - -/* n_hci_tty_open - * - * Called when line discipline changed to N_HCI. - * - * Arguments: - * tty pointer to tty info structure - * Return Value: - * 0 if success, otherwise error code - */ -static int n_hci_tty_open(struct tty_struct *tty) -{ - struct n_hci *n_hci = tty2n_hci(tty); - struct hci_dev *hdev; - - DBG("tty %p", tty); - - if (n_hci) - return -EEXIST; - - if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { - ERR("Can't allocate controll structure"); - return -ENFILE; - } - memset(n_hci, 0, sizeof(struct n_hci)); - - /* Initialize and register HCI device */ - hdev = &n_hci->hdev; - - hdev->type = HCI_UART; - hdev->driver_data = n_hci; - - hdev->open = n_hci_open; - hdev->close = n_hci_close; - hdev->flush = n_hci_flush; - hdev->send = n_hci_send_frame; - - if (hci_register_dev(hdev) < 0) { - ERR("Can't register HCI device %s", hdev->name); - kfree(n_hci); - return -ENODEV; - } - - tty->disc_data = n_hci; - n_hci->tty = tty; - - spin_lock_init(&n_hci->rx_lock); - n_hci->rx_state = WAIT_PACKET_TYPE; - - skb_queue_head_init(&n_hci->txq); - - MOD_INC_USE_COUNT; - - /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - - return 0; -} - -/* n_hci_tty_close() - * - * Called when the line discipline is changed to something - * else, the tty is closed, or the tty detects a hangup. - */ -static void n_hci_tty_close(struct tty_struct *tty) -{ - struct n_hci *n_hci = tty2n_hci(tty); - struct hci_dev *hdev = &n_hci->hdev; - - DBG("tty %p hdev %p", tty, hdev); - - if (n_hci != NULL) { - n_hci_close(hdev); - - if (hci_unregister_dev(hdev) < 0) { - ERR("Can't unregister HCI device %s",hdev->name); - } - - hdev->driver_data = NULL; - tty->disc_data = NULL; - kfree(n_hci); - - MOD_DEC_USE_COUNT; - } -} - -/* n_hci_tty_wakeup() - * - * Callback for transmit wakeup. Called when low level - * device driver can accept more send data. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: None - */ -static void n_hci_tty_wakeup( struct tty_struct *tty ) -{ - struct n_hci *n_hci = tty2n_hci(tty); - - DBG(""); - - if (!n_hci) - return; - - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - if (tty != n_hci->tty) - return; - - n_hci_tx_wakeup(n_hci); -} - -/* n_hci_tty_room() - * - * Callback function from tty driver. Return the amount of - * space left in the receiver's buffer to decide if remote - * transmitter is to be throttled. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: number of bytes left in receive buffer - */ -static int n_hci_tty_room (struct tty_struct *tty) -{ - return 65536; -} - -static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) -{ - register int room = skb_tailroom(n_hci->rx_skb); - - DBG("len %d room %d", len, room); - if (!len) { - DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); - hci_recv_frame(n_hci->rx_skb); - } else if (len > room) { - ERR("Data length is to large"); - kfree_skb(n_hci->rx_skb); - n_hci->hdev.stat.err_rx++; - } else { - n_hci->rx_state = WAIT_DATA; - n_hci->rx_count = len; - return len; - } - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_skb = NULL; - n_hci->rx_count = 0; - return 0; -} - -static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) -{ - register const char *ptr; - hci_event_hdr *eh; - hci_acl_hdr *ah; - hci_sco_hdr *sh; - register int len, type, dlen; - - DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); - - n_hci->hdev.stat.byte_rx += count; - - ptr = data; - while (count) { - if (n_hci->rx_count) { - len = MIN(n_hci->rx_count, count); - memcpy(skb_put(n_hci->rx_skb, len), ptr, len); - n_hci->rx_count -= len; count -= len; ptr += len; - - if (n_hci->rx_count) - continue; - - switch (n_hci->rx_state) { - case WAIT_DATA: - DBG("Complete data"); - - DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); - - hci_recv_frame(n_hci->rx_skb); - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_skb = NULL; - continue; - - case WAIT_EVENT_HDR: - eh = (hci_event_hdr *) n_hci->rx_skb->data; - - DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); - - n_hci_check_data_len(n_hci, eh->plen); - continue; - - case WAIT_ACL_HDR: - ah = (hci_acl_hdr *) n_hci->rx_skb->data; - dlen = __le16_to_cpu(ah->dlen); - - DBG("ACL header: dlen %d", dlen); - - n_hci_check_data_len(n_hci, dlen); - continue; - - case WAIT_SCO_HDR: - sh = (hci_sco_hdr *) n_hci->rx_skb->data; - - DBG("SCO header: dlen %d", sh->dlen); - - n_hci_check_data_len(n_hci, sh->dlen); - continue; - }; - } - - /* WAIT_PACKET_TYPE */ - switch (*ptr) { - case HCI_EVENT_PKT: - DBG("Event packet"); - n_hci->rx_state = WAIT_EVENT_HDR; - n_hci->rx_count = HCI_EVENT_HDR_SIZE; - type = HCI_EVENT_PKT; - break; - - case HCI_ACLDATA_PKT: - DBG("ACL packet"); - n_hci->rx_state = WAIT_ACL_HDR; - n_hci->rx_count = HCI_ACL_HDR_SIZE; - type = HCI_ACLDATA_PKT; - break; - - case HCI_SCODATA_PKT: - DBG("SCO packet"); - n_hci->rx_state = WAIT_SCO_HDR; - n_hci->rx_count = HCI_SCO_HDR_SIZE; - type = HCI_SCODATA_PKT; - break; - - default: - ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); - n_hci->hdev.stat.err_rx++; - ptr++; count--; - continue; - }; - ptr++; count--; - - /* Allocate packet */ - if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_count = 0; - return; - } - n_hci->rx_skb->dev = (void *) &n_hci->hdev; - n_hci->rx_skb->pkt_type = type; - } -} - -/* n_hci_tty_receive() - * - * Called by tty low level driver when receive data is - * available. - * - * Arguments: tty pointer to tty isntance data - * data pointer to received data - * flags pointer to flags for data - * count count of received data in bytes - * - * Return Value: None - */ -static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) -{ - struct n_hci *n_hci = tty2n_hci(tty); - - if (!n_hci || tty != n_hci->tty) - return; - - spin_lock(&n_hci->rx_lock); - n_hci_rx(n_hci, data, flags, count); - spin_unlock(&n_hci->rx_lock); - - if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) - tty->driver.unthrottle(tty); -} - -/* n_hci_tty_ioctl() - * - * Process IOCTL system call for the tty device. - * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object for device - * cmd IOCTL command code - * arg argument for IOCTL call (cmd dependent) - * - * Return Value: Command dependent - */ -static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct n_hci *n_hci = tty2n_hci(tty); - int error = 0; - - DBG(""); - - /* Verify the status of the device */ - if (!n_hci) - return -EBADF; - - switch (cmd) { - default: - error = n_tty_ioctl(tty, file, cmd, arg); - break; - }; - - return error; -} - -/* - * We don't provide read/write/poll interface for user space. - */ -static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) -{ - return 0; -} -static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) -{ - return 0; -} -static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) -{ - return 0; -} - -int __init n_hci_init(void) -{ - static struct tty_ldisc n_hci_ldisc; - int err; - - INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); - - /* Register the tty discipline */ - - memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); - n_hci_ldisc.magic = TTY_LDISC_MAGIC; - n_hci_ldisc.name = "n_hci"; - n_hci_ldisc.open = n_hci_tty_open; - n_hci_ldisc.close = n_hci_tty_close; - n_hci_ldisc.read = n_hci_tty_read; - n_hci_ldisc.write = n_hci_tty_write; - n_hci_ldisc.ioctl = n_hci_tty_ioctl; - n_hci_ldisc.poll = n_hci_tty_poll; - n_hci_ldisc.receive_room= n_hci_tty_room; - n_hci_ldisc.receive_buf = n_hci_tty_receive; - n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; - - if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { - ERR("Can't register HCI line discipline (%d)", err); - return err; - } - - return 0; -} - -void n_hci_cleanup(void) -{ - int err; - - /* Release tty registration of line discipline */ - if ((err = tty_register_ldisc(N_HCI, NULL))) - ERR("Can't unregister HCI line discipline (%d)", err); -} - -module_init(n_hci_init); -module_exit(n_hci_cleanup); - -MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_uart.h Sun May 5 20:39:49 2002 @@ -0,0 +1,80 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef N_HCI +#define N_HCI 15 +#endif + +/* Ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) + +/* UART protocols */ +#define HCI_UART_MAX_PROTO 3 + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_NCSP 2 + +#ifdef __KERNEL__ +struct n_hci; + +struct hci_uart_proto { + unsigned int id; + int (*open)(struct n_hci *n_hci); + int (*recv)(struct n_hci *n_hci, void *data, int len); + int (*send)(struct n_hci *n_hci, void *data, int len); + int (*close)(struct n_hci *n_hci); + int (*flush)(struct n_hci *n_hci); + struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb); +}; + +struct n_hci { + struct tty_struct *tty; + struct hci_dev hdev; + unsigned long flags; + + struct hci_uart_proto *proto; + void *priv; + + struct sk_buff_head txq; + unsigned long tx_state; + spinlock_t rx_lock; +}; + +/* N_HCI flag bits */ +#define N_HCI_PROTO_SET 0x00 + +/* TX states */ +#define N_HCI_SENDING 1 +#define N_HCI_TX_WAKEUP 2 + +int hci_uart_register_proto(struct hci_uart_proto *p); +int hci_uart_unregister_proto(struct hci_uart_proto *p); + +#endif /* __KERNEL__ */ diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Sun May 5 20:39:50 2002 +++ b/drivers/bluetooth/hci_usb.c Sun May 5 20:39:50 2002 @@ -28,570 +28,755 @@ * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * - * $Id: hci_usb.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ + * $Id: hci_usb.c,v 1.6 2002/04/17 17:37:20 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "2.0" #include #include +#define __KERNEL_SYSCALLS__ + #include -#include #include #include #include +#include #include -#include #include -#include -#include #include -#include #include #include -#include -#include #include +#include #include #include -#include #include -#include +#include "hci_usb.h" + +#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) #ifndef HCI_USB_DEBUG -#undef DBG -#define DBG( A... ) -#undef DMP -#define DMP( A... ) +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) #endif +#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET +#undef USB_ZERO_PACKET +#define USB_ZERO_PACKET 0 +#endif + +static struct usb_driver hci_usb_driver; + static struct usb_device_id usb_bluetooth_ids [] = { + /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, + + /* Ericsson with non-standard id */ + { USB_DEVICE(0x0bdb, 0x1002) }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb); -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb); +static void hci_usb_interrupt(struct urb *urb); +static void hci_usb_rx_complete(struct urb *urb); +static void hci_usb_tx_complete(struct urb *urb); -static void hci_usb_unlink_urbs(struct hci_usb *husb) +static struct urb *hci_usb_get_completed(struct hci_usb *husb) { - usb_unlink_urb(husb->read_urb); - usb_unlink_urb(husb->intr_urb); - usb_unlink_urb(husb->ctrl_urb); - usb_unlink_urb(husb->write_urb); + struct sk_buff *skb; + struct urb *urb = NULL; + + skb = skb_dequeue(&husb->completed_q); + if (skb) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + kfree_skb(skb); + } + + BT_DBG("%s urb %p", husb->hdev.name, urb); + return urb; } -static void hci_usb_free_bufs(struct hci_usb *husb) +static int hci_usb_enable_intr(struct hci_usb *husb) { - if (husb->read_urb) { - if (husb->read_urb->transfer_buffer) - kfree(husb->read_urb->transfer_buffer); - usb_free_urb(husb->read_urb); - } + struct urb *urb; + int pipe, size; + void *buf; - if (husb->intr_urb) { - if (husb->intr_urb->transfer_buffer) - kfree(husb->intr_urb->transfer_buffer); - usb_free_urb(husb->intr_urb); - } + BT_DBG("%s", husb->hdev.name); - if (husb->ctrl_urb) - usb_free_urb(husb->ctrl_urb); + if (!(urb = usb_alloc_urb(0, GFP_KERNEL))) + return -ENOMEM; - if (husb->write_urb) - usb_free_urb(husb->write_urb); + if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) { + usb_free_urb(urb); + return -ENOMEM; + } - if (husb->intr_skb) - kfree_skb(husb->intr_skb); + husb->intr_urb = urb; + + pipe = usb_rcvintpipe(husb->udev, husb->intr_ep); + size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe)); + FILL_INT_URB(urb, husb->udev, pipe, buf, size, + hci_usb_interrupt, husb, husb->intr_interval); + + return usb_submit_urb(urb, GFP_KERNEL); } -/* ------- Interface to HCI layer ------ */ -/* Initialize device */ -int hci_usb_open(struct hci_dev *hdev) +static int hci_usb_disable_intr(struct hci_usb *husb) { - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int status; - - DBG("%s", hdev->name); + struct urb *urb = husb->intr_urb; + struct sk_buff *skb; - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL))) - DBG("read submit failed. %d", status); + BT_DBG("%s", husb->hdev.name); - husb->intr_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->intr_urb, GFP_KERNEL))) - DBG("interrupt submit failed. %d", status); + usb_unlink_urb(urb); usb_free_urb(urb); + husb->intr_urb = NULL; - hdev->flags |= HCI_RUNNING; + skb = husb->intr_skb; + if (skb) { + husb->intr_skb = NULL; + kfree_skb(skb); + } return 0; } -/* Reset device */ -int hci_usb_flush(struct hci_dev *hdev) +static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + struct hci_usb_scb *scb; + struct sk_buff *skb; + int pipe, size, err; - DBG("%s", hdev->name); + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - /* Drop TX queues */ - skb_queue_purge(&husb->tx_ctrl_q); - skb_queue_purge(&husb->tx_write_q); + size = HCI_MAX_FRAME_SIZE; - return 0; + if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + BT_DBG("%s urb %p", husb->hdev.name, urb); + + skb->dev = (void *) &husb->hdev; + skb->pkt_type = HCI_ACLDATA_PKT; + + scb = (struct hci_usb_scb *) skb->cb; + scb->urb = urb; + + pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK; + + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s bulk rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); + } + return err; } -/* Close device */ -int hci_usb_close(struct hci_dev *hdev) +/* Initialize device */ +static int hci_usb_open(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int i, err; + long flags; - DBG("%s", hdev->name); + BT_DBG("%s", hdev->name); - hdev->flags &= ~HCI_RUNNING; - hci_usb_unlink_urbs(husb); + if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) + return 0; - hci_usb_flush(hdev); + write_lock_irqsave(&husb->completion_lock, flags); - return 0; + err = hci_usb_enable_intr(husb); + if (!err) { + for (i = 0; i < HCI_MAX_BULK_TX; i++) + hci_usb_rx_submit(husb, NULL); + } else + clear_bit(HCI_RUNNING, &hdev->flags); + + write_unlock_irqrestore(&husb->completion_lock, flags); + return err; } -void hci_usb_ctrl_wakeup(struct hci_usb *husb) +/* Reset device */ +static int hci_usb_flush(struct hci_dev *hdev) { - struct sk_buff *skb; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state)) - return; + BT_DBG("%s", hdev->name); - DBG("%s", husb->hdev.name); + skb_queue_purge(&husb->cmd_q); + skb_queue_purge(&husb->acl_q); + return 0; +} - if (!(skb = skb_dequeue(&husb->tx_ctrl_q))) - goto done; +static inline void hci_usb_unlink_urbs(struct hci_usb *husb) +{ + struct sk_buff *skb; + struct urb *urb; - if (hci_usb_ctrl_msg(husb, skb)){ + BT_DBG("%s", husb->hdev.name); + + while ((skb = skb_dequeue(&husb->pending_q))) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + usb_unlink_urb(urb); kfree_skb(skb); - goto done; } - DMP(skb->data, skb->len); + while ((urb = hci_usb_get_completed(husb))) + usb_free_urb(urb); +} - husb->hdev.stat.byte_tx += skb->len; - return; +/* Close device */ +static int hci_usb_close(struct hci_dev *hdev) +{ + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + long flags; + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; -done: - clear_bit(HCI_TX_CTRL, &husb->tx_state); - return; + BT_DBG("%s", hdev->name); + + write_lock_irqsave(&husb->completion_lock, flags); + + hci_usb_disable_intr(husb); + hci_usb_unlink_urbs(husb); + hci_usb_flush(hdev); + + write_unlock_irqrestore(&husb->completion_lock, flags); + return 0; } -void hci_usb_write_wakeup(struct hci_usb *husb) +static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) { - struct sk_buff *skb; + struct hci_usb_scb *scb = (void *) skb->cb; + struct urb *urb = hci_usb_get_completed(husb); + struct usb_ctrlrequest *cr; + int pipe, err; - if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state)) - return; + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - DBG("%s", husb->hdev.name); + if (!(cr = kmalloc(sizeof(*cr), GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + pipe = usb_sndctrlpipe(husb->udev, 0); - if (!(skb = skb_dequeue(&husb->tx_write_q))) - goto done; + cr->bRequestType = HCI_CTRL_REQ; + cr->bRequest = 0; + cr->wIndex = 0; + cr->wValue = 0; + cr->wLength = __cpu_to_le16(skb->len); - if (hci_usb_write_msg(husb, skb)) { - skb_queue_head(&husb->tx_write_q, skb); - goto done; - } + FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) cr, + skb->data, skb->len, hci_usb_tx_complete, skb); - DMP(skb->data, skb->len); + BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - husb->hdev.stat.byte_tx += skb->len; - return; + scb->urb = urb; -done: - clear_bit(HCI_TX_WRITE, &husb->tx_state); - return; + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s ctrl tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); kfree(cr); + } + return err; } -/* Send frames from HCI layer */ -int hci_usb_send_frame(struct sk_buff *skb) +static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) { - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb; - - if (!hdev) { - ERR("frame for uknown device (hdev=NULL)"); - return -ENODEV; - } + struct hci_usb_scb *scb = (void *) skb->cb; + struct urb *urb = hci_usb_get_completed(husb); + int pipe, err; - if (!(hdev->flags & HCI_RUNNING)) - return 0; + if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) + return -ENOMEM; - husb = (struct hci_usb *) hdev->driver_data; + pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, + hci_usb_tx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; - DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - skb_queue_tail(&husb->tx_ctrl_q, skb); - hci_usb_ctrl_wakeup(husb); - hdev->stat.cmd_tx++; - return 0; - - case HCI_ACLDATA_PKT: - skb_queue_tail(&husb->tx_write_q, skb); - hci_usb_write_wakeup(husb); - hdev->stat.acl_tx++; - return 0; - - case HCI_SCODATA_PKT: - return -EOPNOTSUPP; - }; + scb->urb = urb; - return 0; + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s bulk tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); + } + return err; } -/* ---------- USB ------------- */ - -static void hci_usb_ctrl(struct urb *urb) +static void hci_usb_tx_process(struct hci_usb *husb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; - struct hci_usb *husb; - - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; - husb = (struct hci_usb *) hdev->driver_data; + struct sk_buff *skb; - DBG("%s", hdev->name); + BT_DBG("%s", husb->hdev.name); - if (urb->status) - DBG("%s ctrl status: %d", hdev->name, urb->status); + do { + clear_bit(HCI_USB_TX_WAKEUP, &husb->state); + + /* Process ACL queue */ + while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING && + (skb = skb_dequeue(&husb->acl_q))) { + if (hci_usb_send_bulk(husb, skb) < 0) { + skb_queue_head(&husb->acl_q, skb); + break; + } + } - clear_bit(HCI_TX_CTRL, &husb->tx_state); - kfree_skb(skb); + /* Process command queue */ + if (!test_bit(HCI_USB_CTRL_TX, &husb->state) && + (skb = skb_dequeue(&husb->cmd_q)) != NULL) { + set_bit(HCI_USB_CTRL_TX, &husb->state); + if (hci_usb_send_ctrl(husb, skb) < 0) { + skb_queue_head(&husb->cmd_q, skb); + clear_bit(HCI_USB_CTRL_TX, &husb->state); + } + } + } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); +} - /* Wake up device */ - hci_usb_ctrl_wakeup(husb); +static inline void hci_usb_tx_wakeup(struct hci_usb *husb) +{ + /* Serialize TX queue processing to avoid data reordering */ + if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { + hci_usb_tx_process(husb); + clear_bit(HCI_USB_TX_PROCESS, &husb->state); + } else + set_bit(HCI_USB_TX_WAKEUP, &husb->state); } -static void hci_usb_bulk_write(struct urb *urb) +/* Send frames from HCI layer */ +int hci_usb_send_frame(struct sk_buff *skb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct hci_usb *husb; - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; + if (!hdev) { + BT_ERR("frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + husb = (struct hci_usb *) hdev->driver_data; - DBG("%s", hdev->name); + BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - if (urb->status) - DBG("%s bulk write status: %d", hdev->name, urb->status); + read_lock(&husb->completion_lock); - clear_bit(HCI_TX_WRITE, &husb->tx_state); - kfree_skb(skb); + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + skb_queue_tail(&husb->cmd_q, skb); + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + skb_queue_tail(&husb->acl_q, skb); + hdev->stat.acl_tx++; + break; - /* Wake up device */ - hci_usb_write_wakeup(husb); + case HCI_SCODATA_PKT: + default: + kfree_skb(skb); + break; + } + hci_usb_tx_wakeup(husb); - return; + read_unlock(&husb->completion_lock); + return 0; } -static void hci_usb_intr(struct urb *urb) +static void hci_usb_interrupt(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - register int count = urb->actual_length; - register struct sk_buff *skb = husb->intr_skb; + struct hci_usb *husb = (void *) urb->context; + struct hci_usb_scb *scb; + struct sk_buff *skb; hci_event_hdr *eh; - register int len; + __u8 *data = urb->transfer_buffer; + int count = urb->actual_length; + int len = HCI_EVENT_HDR_SIZE; - if (!husb) - return; + BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count); - DBG("%s count %d", husb->hdev.name, count); + if (!test_bit(HCI_RUNNING, &husb->hdev.flags)) + return; if (urb->status || !count) { - DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); + BT_DBG("%s intr status %d, count %d", + husb->hdev.name, urb->status, count); return; } - /* Do we really have to handle continuations here ? */ - if (!skb) { - /* New frame */ - if (count < HCI_EVENT_HDR_SIZE) { - DBG("%s bad frame len %d", husb->hdev.name, count); - return; - } + read_lock(&husb->completion_lock); + + husb->hdev.stat.byte_rx += count; + + if (!(skb = husb->intr_skb)) { + /* Start of the frame */ + if (count < HCI_EVENT_HDR_SIZE) + goto bad_len; - eh = (hci_event_hdr *) data; + eh = (hci_event_hdr *) data; len = eh->plen + HCI_EVENT_HDR_SIZE; - if (count > len) { - DBG("%s corrupted frame, len %d", husb->hdev.name, count); - return; - } + if (count > len) + goto bad_len; - /* Allocate skb */ - if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); - return; + skb = bluez_skb_alloc(len, GFP_ATOMIC); + if (!skb) { + BT_ERR("%s no memory for event packet", husb->hdev.name); + goto done; } + scb = (void *) skb->cb; + skb->dev = (void *) &husb->hdev; skb->pkt_type = HCI_EVENT_PKT; husb->intr_skb = skb; - husb->intr_count = len; + scb->intr_len = len; } else { /* Continuation */ - if (count > husb->intr_count) { - ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); - - kfree_skb(skb); + scb = (void *) skb->cb; + len = scb->intr_len; + if (count > len) { husb->intr_skb = NULL; - husb->intr_count = 0; - return; + kfree_skb(skb); + goto bad_len; } } memcpy(skb_put(skb, count), data, count); - husb->intr_count -= count; + scb->intr_len -= count; - DMP(data, count); + if (!scb->intr_len) { + /* Complete frame */ + husb->intr_skb = NULL; + hci_recv_frame(skb); + } - if (!husb->intr_count) { - /* Got complete frame */ +done: + read_unlock(&husb->completion_lock); + return; - husb->hdev.stat.byte_rx += skb->len; - hci_recv_frame(skb); +bad_len: + BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len); + husb->hdev.stat.err_rx++; + read_unlock(&husb->completion_lock); +} - husb->intr_skb = NULL; +static void hci_usb_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + + BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb, + urb->status, urb->transfer_flags); + + if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) { + kfree(urb->setup_packet); + clear_bit(HCI_USB_CTRL_TX, &husb->state); } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return; + + read_lock(&husb->completion_lock); + + if (!urb->status) + husb->hdev.stat.byte_tx += skb->len; + else + husb->hdev.stat.err_tx++; + + skb_unlink(skb); + skb_queue_tail(&husb->completed_q, skb); + hci_usb_tx_wakeup(husb); + + read_unlock(&husb->completion_lock); + return; } -static void hci_usb_bulk_read(struct urb *urb) +static void hci_usb_rx_complete(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - int count = urb->actual_length, status; - struct sk_buff *skb; + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int status, count = urb->actual_length; hci_acl_hdr *ah; - register __u16 dlen; + int dlen, size; - if (!husb) + BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb, + urb->status, count, urb->transfer_flags); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) return; - DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); + read_lock(&husb->completion_lock); - if (urb->status) { - /* Do not re-submit URB on critical errors */ - switch (urb->status) { - case -ENOENT: - return; - default: - goto resubmit; - }; - } - if (!count) + if (urb->status || !count) goto resubmit; - DMP(data, count); + husb->hdev.stat.byte_rx += count; - ah = (hci_acl_hdr *) data; - dlen = le16_to_cpu(ah->dlen); + ah = (hci_acl_hdr *) skb->data; + dlen = __le16_to_cpu(ah->dlen); + size = HCI_ACL_HDR_SIZE + dlen; /* Verify frame len and completeness */ - if ((count - HCI_ACL_HDR_SIZE) != dlen) { - ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); - goto resubmit; - } - - /* Allocate packet */ - if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); + if (count != size) { + BT_ERR("%s corrupted ACL packet: count %d, dlen %d", + husb->hdev.name, count, dlen); + bluez_dump("hci_usb", skb->data, count); + husb->hdev.stat.err_rx++; goto resubmit; } - memcpy(skb_put(skb, count), data, count); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_ACLDATA_PKT; - - husb->hdev.stat.byte_rx += skb->len; - + skb_unlink(skb); + skb_put(skb, count); hci_recv_frame(skb); -resubmit: - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL))) - DBG("%s read URB submit failed %d", husb->hdev.name, status); + hci_usb_rx_submit(husb, urb); - DBG("%s read URB re-submited", husb->hdev.name); + read_unlock(&husb->completion_lock); + return; + +resubmit: + urb->dev = husb->udev; + status = usb_submit_urb(urb, GFP_ATOMIC); + BT_DBG("%s URB resubmit status %d", husb->hdev.name, status); + read_unlock(&husb->completion_lock); } -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) +static void hci_usb_destruct(struct hci_dev *hdev) { - struct urb *urb = husb->ctrl_urb; - struct usb_ctrlrequest *dr = &husb->dev_req; - int pipe, status; + struct hci_usb *husb; - DBG("%s len %d", husb->hdev.name, skb->len); + if (!hdev) return; - pipe = usb_sndctrlpipe(husb->udev, 0); + BT_DBG("%s", hdev->name); - dr->bRequestType = HCI_CTRL_REQ; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = cpu_to_le16(skb->len); - - FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, - hci_usb_ctrl, skb); - - if ((status = usb_submit_urb(urb, GFP_KERNEL))) { - DBG("%s control URB submit failed %d", husb->hdev.name, status); - return status; - } + husb = (struct hci_usb *) hdev->driver_data; + kfree(husb); - return 0; + MOD_DEC_USE_COUNT; } -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb) +#ifdef CONFIG_BLUEZ_USB_FW_LOAD + +/* Support for user mode Bluetooth USB firmware loader */ + +#define FW_LOADER "/sbin/bluefw" +static int errno; + +static int hci_usb_fw_exec(void *dev) { - struct urb *urb = husb->write_urb; - int pipe, status; + char *envp[] = { "HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { FW_LOADER, dev, NULL }; + int err; - DBG("%s len %d", husb->hdev.name, skb->len); + err = exec_usermodehelper(FW_LOADER, argv, envp); + if (err) + BT_ERR("failed to exec %s %s", FW_LOADER, (char *)dev); + return err; +} - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr); +static int hci_usb_fw_load(struct usb_device *udev) +{ + sigset_t tmpsig; + char dev[16]; + pid_t pid; + int result; - FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_bulk_write, skb); - urb->transfer_flags |= USB_QUEUE_BULK; + /* Check if root fs is mounted */ + if (!current->fs->root) { + BT_ERR("root fs not mounted"); + return -EPERM; + } - if ((status = usb_submit_urb(urb, GFP_KERNEL))) { - DBG("%s write URB submit failed %d", husb->hdev.name, status); - return status; + sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum); + + pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0); + if (pid < 0) { + BT_ERR("fork failed, errno %d\n", -pid); + return pid; } + /* Block signals, everything but SIGKILL/SIGSTOP */ + spin_lock_irq(¤t->sigmask_lock); + tmpsig = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + result = waitpid(pid, NULL, __WCLONE); + + /* Allow signals again */ + spin_lock_irq(¤t->sigmask_lock); + current->blocked = tmpsig; + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + if (result != pid) { + BT_ERR("waitpid failed pid %d errno %d\n", pid, -result); + return -result; + } return 0; } +#endif /* CONFIG_BLUEZ_USB_FW_LOAD */ + static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep; + struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM]; struct usb_interface_descriptor *uif; struct usb_endpoint_descriptor *ep; + struct usb_interface *iface, *isoc_iface; struct hci_usb *husb; struct hci_dev *hdev; - int i, size, pipe; - __u8 * buf; + int i, a, e, size, ifn, isoc_ifnum, isoc_alts; - DBG("udev %p ifnum %d", udev, ifnum); + BT_DBG("udev %p ifnum %d", udev, ifnum); - /* Check device signature */ - if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) || - (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)|| - (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) ) + /* Check number of endpoints */ + if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3) return NULL; MOD_INC_USE_COUNT; - uif = &udev->actconfig->interface[ifnum].altsetting[0]; - - if (uif->bNumEndpoints != 3) { - DBG("Wrong number of endpoints %d", uif->bNumEndpoints); - MOD_DEC_USE_COUNT; - return NULL; - } - - bulk_out_ep = intr_in_ep = bulk_in_ep = NULL; +#ifdef CONFIG_BLUEZ_USB_FW_LOAD + hci_usb_fw_load(udev); +#endif + memset(bulk_out_ep, 0, sizeof(bulk_out_ep)); + memset(isoc_out_ep, 0, sizeof(isoc_out_ep)); + memset(bulk_in_ep, 0, sizeof(bulk_in_ep)); + memset(isoc_in_ep, 0, sizeof(isoc_in_ep)); + memset(intr_in_ep, 0, sizeof(intr_in_ep)); + + size = 0; + isoc_iface = NULL; + isoc_alts = isoc_ifnum = 0; + /* Find endpoints that we need */ - for ( i = 0; i < uif->bNumEndpoints; ++i) { - ep = &uif->endpoint[i]; - switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (ep->bEndpointAddress & USB_DIR_IN) - bulk_in_ep = ep; - else - bulk_out_ep = ep; - break; + ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); + for (i = 0; i < ifn; i++) { + iface = &udev->actconfig->interface[i]; + for (a = 0; a < iface->num_altsetting; a++) { + uif = &iface->altsetting[a]; + for (e = 0; e < uif->bNumEndpoints; e++) { + ep = &uif->endpoint[e]; + + switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_INT: + if (ep->bEndpointAddress & USB_DIR_IN) + intr_in_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_BULK: + if (ep->bEndpointAddress & USB_DIR_IN) + bulk_in_ep[i] = ep; + else + bulk_out_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_ISOC: + if (ep->wMaxPacketSize < size) + break; + size = ep->wMaxPacketSize; + + isoc_iface = iface; + isoc_alts = a; + isoc_ifnum = i; + + if (ep->bEndpointAddress & USB_DIR_IN) + isoc_in_ep[i] = ep; + else + isoc_out_ep[i] = ep; + break; + } + } + } + } - case USB_ENDPOINT_XFER_INT: - intr_in_ep = ep; - break; - }; + if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) { + BT_DBG("Bulk endpoints not found"); + goto done; } - if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { - DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep); - MOD_DEC_USE_COUNT; - return NULL; + if (!isoc_in_ep[1] || !isoc_out_ep[1]) { + BT_DBG("Isoc endpoints not found"); + isoc_iface = NULL; } if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { - ERR("Can't allocate: control structure"); - MOD_DEC_USE_COUNT; - return NULL; + BT_ERR("Can't allocate: control structure"); + goto done; } memset(husb, 0, sizeof(struct hci_usb)); husb->udev = udev; - husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress; - - if (!(husb->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: control URB"); - goto probe_error; - } - - if (!(husb->write_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: write URB"); - goto probe_error; - } - - if (!(husb->read_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: read URB"); - goto probe_error; - } - - ep = bulk_in_ep; - pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress); - size = HCI_MAX_FRAME_SIZE; - - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: read buffer"); - goto probe_error; - } - - FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb); - husb->read_urb->transfer_flags |= USB_QUEUE_BULK; + husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress; + husb->bulk_in_ep = bulk_in_ep[0]->bEndpointAddress; - ep = intr_in_ep; - pipe = usb_rcvintpipe(udev, ep->bEndpointAddress); - size = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + husb->intr_ep = intr_in_ep[0]->bEndpointAddress; + husb->intr_interval = intr_in_ep[0]->bInterval; - if (!(husb->intr_urb = usb_alloc_urb(0, GFP_KERNEL))) { - ERR("Can't allocate: interrupt URB"); - goto probe_error; - } + if (isoc_iface) { + if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { + BT_ERR("Can't set isoc interface settings"); + isoc_iface = NULL; + } + usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); + husb->isoc_iface = isoc_iface; - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: interrupt buffer"); - goto probe_error; + husb->isoc_in_ep = isoc_in_ep[1]->bEndpointAddress; + husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress; } - FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval); - - skb_queue_head_init(&husb->tx_ctrl_q); - skb_queue_head_init(&husb->tx_write_q); + husb->completion_lock = RW_LOCK_UNLOCKED; + + skb_queue_head_init(&husb->acl_q); + skb_queue_head_init(&husb->cmd_q); + skb_queue_head_init(&husb->pending_q); + skb_queue_head_init(&husb->completed_q); /* Initialize and register HCI device */ hdev = &husb->hdev; @@ -602,18 +787,20 @@ hdev->open = hci_usb_open; hdev->close = hci_usb_close; hdev->flush = hci_usb_flush; - hdev->send = hci_usb_send_frame; + hdev->send = hci_usb_send_frame; + hdev->destruct = hci_usb_destruct; if (hci_register_dev(hdev) < 0) { - ERR("Can't register HCI device %s", hdev->name); + BT_ERR("Can't register HCI device"); goto probe_error; } return husb; probe_error: - hci_usb_free_bufs(husb); kfree(husb); + +done: MOD_DEC_USE_COUNT; return NULL; } @@ -626,22 +813,18 @@ if (!husb) return; - DBG("%s", hdev->name); + BT_DBG("%s", hdev->name); hci_usb_close(hdev); - if (hci_unregister_dev(hdev) < 0) { - ERR("Can't unregister HCI device %s", hdev->name); - } + if (husb->isoc_iface) + usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - hci_usb_free_bufs(husb); - kfree(husb); - - MOD_DEC_USE_COUNT; + if (hci_unregister_dev(hdev) < 0) + BT_ERR("Can't unregister HCI device %s", hdev->name); } -static struct usb_driver hci_usb_driver = -{ +static struct usb_driver hci_usb_driver = { name: "hci_usb", probe: hci_usb_probe, disconnect: hci_usb_disconnect, @@ -652,12 +835,12 @@ { int err; - INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); if ((err = usb_register(&hci_usb_driver)) < 0) - ERR("Failed to register HCI USB driver"); + BT_ERR("Failed to register HCI USB driver"); return err; } diff -Nru a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_usb.h Sun May 5 20:39:50 2002 @@ -0,0 +1,79 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $ + */ + +#ifdef __KERNEL__ + +/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +#define HCI_DEV_CLASS 0xe0 /* Wireless class */ +#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ +#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ + +#define HCI_CTRL_REQ 0x20 + +#define HCI_MAX_IFACE_NUM 3 + +#define HCI_MAX_BULK_TX 4 +#define HCI_MAX_BULK_RX 1 + +struct hci_usb { + struct hci_dev hdev; + + unsigned long state; + + struct usb_device *udev; + struct usb_interface *isoc_iface; + + __u8 bulk_out_ep; + __u8 bulk_in_ep; + __u8 isoc_out_ep; + __u8 isoc_in_ep; + + __u8 intr_ep; + __u8 intr_interval; + struct urb * intr_urb; + struct sk_buff * intr_skb; + + rwlock_t completion_lock; + + struct sk_buff_head cmd_q; // TX Commands + struct sk_buff_head acl_q; // TX ACLs + struct sk_buff_head pending_q; // Pending requests + struct sk_buff_head completed_q; // Completed requests +}; + +struct hci_usb_scb { + struct urb *urb; + int intr_len; +}; + +/* States */ +#define HCI_USB_TX_PROCESS 1 +#define HCI_USB_TX_WAKEUP 2 +#define HCI_USB_CTRL_TX 3 + +#endif /* __KERNEL__ */ diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c --- a/drivers/bluetooth/hci_vhci.c Sun May 5 20:39:50 2002 +++ b/drivers/bluetooth/hci_vhci.c Sun May 5 20:39:50 2002 @@ -25,9 +25,9 @@ /* * BlueZ HCI virtual device driver. * - * $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ + * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "1.1" #include #include @@ -49,43 +49,56 @@ #include #include -#include #include -#include +#include "hci_vhci.h" /* HCI device part */ -int hci_vhci_open(struct hci_dev *hdev) +static int hci_vhci_open(struct hci_dev *hdev) { - hdev->flags |= HCI_RUNNING; + set_bit(HCI_RUNNING, &hdev->flags); return 0; } -int hci_vhci_flush(struct hci_dev *hdev) +static int hci_vhci_flush(struct hci_dev *hdev) { struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; skb_queue_purge(&hci_vhci->readq); return 0; } -int hci_vhci_close(struct hci_dev *hdev) +static int hci_vhci_close(struct hci_dev *hdev) { - hdev->flags &= ~HCI_RUNNING; + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + hci_vhci_flush(hdev); return 0; } -int hci_vhci_send_frame(struct sk_buff *skb) +static void hci_vhci_destruct(struct hci_dev *hdev) +{ + struct hci_vhci_struct *vhci; + + if (!hdev) return; + + vhci = (struct hci_vhci_struct *) hdev->driver_data; + kfree(vhci); + + MOD_DEC_USE_COUNT; +} + +static int hci_vhci_send_frame(struct sk_buff *skb) { struct hci_dev* hdev = (struct hci_dev *) skb->dev; struct hci_vhci_struct *hci_vhci; if (!hdev) { - ERR("Frame for uknown device (hdev=NULL)"); + BT_ERR("Frame for uknown device (hdev=NULL)"); return -ENODEV; } - if (!(hdev->flags & HCI_RUNNING)) + if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; @@ -188,7 +201,7 @@ add_wait_queue(&hci_vhci->read_wait, &wait); while (count) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* Read frames from device queue */ if (!(skb = skb_dequeue(&hci_vhci->readq))) { @@ -214,13 +227,17 @@ kfree_skb(skb); break; } - - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&hci_vhci->read_wait, &wait); return ret; } +static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -265,11 +282,13 @@ hdev->close = hci_vhci_close; hdev->flush = hci_vhci_flush; hdev->send = hci_vhci_send_frame; + hdev->destruct = hci_vhci_destruct; if (hci_register_dev(hdev) < 0) { kfree(hci_vhci); return -EBUSY; } + MOD_INC_USE_COUNT; file->private_data = hci_vhci; return 0; @@ -280,18 +299,16 @@ struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; if (hci_unregister_dev(&hci_vhci->hdev) < 0) { - ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); + BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); } - kfree(hci_vhci); file->private_data = NULL; - return 0; } static struct file_operations hci_vhci_fops = { owner: THIS_MODULE, - llseek: no_llseek, + llseek: hci_vhci_chr_lseek, read: hci_vhci_chr_read, write: hci_vhci_chr_write, poll: hci_vhci_chr_poll, @@ -310,12 +327,12 @@ int __init hci_vhci_init(void) { - INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); if (misc_register(&hci_vhci_miscdev)) { - ERR("Can't register misc device %d\n", VHCI_MINOR); + BT_ERR("Can't register misc device %d\n", VHCI_MINOR); return -EIO; } @@ -332,4 +349,4 @@ MODULE_AUTHOR("Maxim Krasnyansky "); MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/bluetooth/hci_vhci.h b/drivers/bluetooth/hci_vhci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/bluetooth/hci_vhci.h Sun May 5 20:39:50 2002 @@ -0,0 +1,50 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef __HCI_VHCI_H +#define __HCI_VHCI_H + +#ifdef __KERNEL__ + +struct hci_vhci_struct { + struct hci_dev hdev; + __u32 flags; + wait_queue_head_t read_wait; + struct sk_buff_head readq; + struct fasync_struct *fasync; +}; + +/* VHCI device flags */ +#define VHCI_FASYNC 0x0010 + +#endif /* __KERNEL__ */ + +#define VHCI_DEV "/dev/vhci" +#define VHCI_MINOR 250 + +#endif /* __HCI_VHCI_H */ diff -Nru a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c --- a/drivers/char/i810-tco.c Sun May 5 20:39:49 2002 +++ b/drivers/char/i810-tco.c Sun May 5 20:39:49 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.03: TCO timer driver for i810 chipsets + * i810-tco 0.04: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -17,20 +17,25 @@ * developed for * Jentro AG, Haar/Munich (Germany) * - * TCO timer driver for i810/i815 chipsets + * TCO timer driver for i8xx chipsets * based on softdog.c by Alan Cox * - * The TCO timer is implemented in the 82801AA (82801AB) chip, - * see intel documentation from http://developer.intel.com, - * order number 290655-003 + * The TCO timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 82801AA & 82801AB chip : document number 290655-003, 290677-004, + * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, + * 82801CA & 82801CAM chip : document number 290716-001, 290718-001 * * 20000710 Nils Faerber * Initial Version 0.01 * 20000728 Nils Faerber * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups * 20011214 Matt Domsch - * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Didn't add timeout option as i810_margin already exists. + * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option as i810_margin already exists. + * 20020224 Joel Becker, Wim Van Sebroeck + * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3, + * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. */ #include @@ -49,13 +54,13 @@ #include "i810-tco.h" -/* Just in case that the PCI vendor and device IDs are not yet defined */ -#ifndef PCI_DEVICE_ID_INTEL_82801AA_0 -#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 -#endif +/* Module and version information */ +#define TCO_VERSION "0.04" +#define TCO_MODULE_NAME "i810 TCO timer" +#define TCO_DRIVER_NAME TCO_MODULE_NAME " , " TCO_VERSION /* Default expire timeout */ -#define TIMER_MARGIN 50 /* steps of 0.6sec, 2 0x3f || tmrval < 0x03) + if (tmrval > 0x3f || tmrval < 0x04) return -1; spin_lock(&tco_lock); @@ -226,8 +231,10 @@ static int i810tco_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int new_margin, u_margin; + static struct watchdog_info ident = { - 0, + WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 0, "i810 TCO timer" }; @@ -247,6 +254,19 @@ case WDIOC_KEEPALIVE: tco_timer_reload (); return 0; + case WDIOC_SETTIMEOUT: + if (get_user(u_margin, (int *) arg)) + return -EFAULT; + new_margin = (u_margin * 10 + 5) / 6; + if ((new_margin < 4) || (new_margin > 63)) + return -EINVAL; + if (tco_timer_settimer((unsigned char)new_margin)) + return -EINVAL; + i810_margin = new_margin; + tco_timer_reload(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user((int)(i810_margin * 6 / 10), (int *) arg); } } @@ -263,6 +283,8 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); @@ -297,7 +319,7 @@ ACPIBASE = badr; /* Something's wrong here, ACPIBASE has to be set */ if (badr == 0x0001 || badr == 0x0000) { - printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n"); + printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n"); return 0; } /* @@ -309,7 +331,7 @@ pci_write_config_byte (i810tco_pci, 0xd4, val1); pci_read_config_byte (i810tco_pci, 0xd4, &val1); if (val1 & 0x02) { - printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); + printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); return 0; /* Cannot reset NO_REBOOT bit */ } } @@ -346,22 +368,22 @@ if (!i810tco_getdevice () || i810tco_pci == NULL) return -ENODEV; if (!request_region (TCOBASE, 0x10, "i810 TCO")) { - printk (KERN_ERR - "i810 TCO timer: I/O address 0x%04x already in use\n", + printk (KERN_ERR TCO_MODULE_NAME + ": I/O address 0x%04x already in use\n", TCOBASE); return -EIO; } if (misc_register (&i810tco_miscdev) != 0) { release_region (TCOBASE, 0x10); - printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n"); + printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n"); return -EIO; } tco_timer_settimer ((unsigned char) i810_margin); tco_timer_reload (); - printk (KERN_INFO - "i810 TCO timer: V0.03, timer margin: %d sec (0x%04x), nowayout: %d\n", - (int) (i810_margin * 6 / 10), TCOBASE, nowayout); + printk (KERN_INFO TCO_DRIVER_NAME + ": timer margin: %d sec (0x%04x)\n", + (int) (i810_margin * 6 / 10), TCOBASE); return 0; } diff -Nru a/drivers/char/i810-tco.h b/drivers/char/i810-tco.h --- a/drivers/char/i810-tco.h Sun May 5 20:39:49 2002 +++ b/drivers/char/i810-tco.h Sun May 5 20:39:49 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.02: TCO timer driver for i810 chipsets + * i810-tco 0.04: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -17,12 +17,14 @@ * developed for * Jentro AG, Haar/Munich (Germany) * - * TCO timer driver for i810 chipsets + * TCO timer driver for i8xx chipsets * based on softdog.c by Alan Cox * - * The TCO timer is implemented in the 82801AA (82801AB) chip, - * see intel documentation from http://developer.intel.com, - * order number 290655-003 + * The TCO timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 82801AA & 82801AB chip : document number 290655-003, 290677-004, + * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, + * 82801CA & 82801CAM chip : document number 290716-001, 290718-001 * * For history see i810-tco.c */ diff -Nru a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c --- a/drivers/char/i810_rng.c Sun May 5 20:39:49 2002 +++ b/drivers/char/i810_rng.c Sun May 5 20:39:49 2002 @@ -35,7 +35,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.7" +#define RNG_VERSION "0.9.8" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -336,6 +336,7 @@ { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, rng_pci_tbl); diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help --- a/drivers/ide/Config.help Sun May 5 20:39:50 2002 +++ b/drivers/ide/Config.help Sun May 5 20:39:50 2002 @@ -751,6 +751,37 @@ Generally say N here. +CONFIG_BLK_DEV_IDE_TCQ + Support for tagged command queueing on ATA disk drives. This enables + the IDE layer to have multiple in-flight requests on hardware that + supports it. For now this includes the IBM Deskstar series drives, + such as the 22GXP, 75GXP, 40GV, 60GXP, and 120GXP (ie any Deskstar made + in the last couple of years), and at least some of the Western + Digital drives in the Expert series (by nature of really being IBM + drives). + + If you have such a drive, say Y here. + +CONFIG_BLK_DEV_IDE_TCQ_DEPTH + Maximum size of commands to enable per-drive. Any value between 1 + and 32 is valid, with 32 being the maxium that the hardware supports. + + You probably just want the default of 32 here. If you enter an invalid + number, the default value will be used. + +CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + Enabled tagged command queueing unconditionally on drives that report + support for it. Regardless of the chosen value here, tagging can be + controlled at run time: + + echo "using_tcq:32" > /proc/ide/hdX/settings + + where any value between 1-32 selects chosen queue depth and enables + TCQ, and 0 disables it. hdparm version 4.7 an above also support + TCQ manipulations. + + Generally say Y here. + CONFIG_BLK_DEV_IT8172 Say Y here to support the on-board IDE controller on the Integrated Technology Express, Inc. ITE8172 SBC. Vendor page at diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in --- a/drivers/ide/Config.in Sun May 5 20:39:50 2002 +++ b/drivers/ide/Config.in Sun May 5 20:39:50 2002 @@ -33,20 +33,25 @@ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI - comment 'IDE chipset support' + comment 'ATA host chipset support' dep_bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 dep_bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640 - dep_bool ' ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP + dep_bool ' ISA-PNP support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP if [ "$CONFIG_PCI" = "y" ]; then dep_bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86 - bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI + bool ' PCI host chipset support' CONFIG_BLK_DEV_IDEPCI if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD - bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ + bool ' Sharing PCI ATA interrupts support' CONFIG_IDEPCI_SHARE_IRQ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL + dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ + if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then + int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32 + fi dep_bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX @@ -77,11 +82,9 @@ dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' VIA chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEDMA_PCI fi - if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then - bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 - fi fi if [ "$CONFIG_ALL_PPC" = "y" ]; then bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile --- a/drivers/ide/Makefile Sun May 5 20:39:50 2002 +++ b/drivers/ide/Makefile Sun May 5 20:39:50 2002 @@ -10,7 +10,7 @@ O_TARGET := idedriver.o -export-objs := ide-taskfile.o ide.o ide-features.o ide-probe.o ataraid.o +export-objs := ide-taskfile.o ide.o ide-features.o ide-probe.o ide-dma.o ataraid.o obj-y := obj-m := @@ -44,6 +44,7 @@ ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o +ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ) += tcq.o ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c --- a/drivers/ide/aec62xx.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/aec62xx.c Sun May 5 20:39:49 2002 @@ -310,7 +310,7 @@ byte speed = -1; if (drive->type != ATA_DISK) - return ide_dma_off_quietly; + return 0; if (((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008) || @@ -333,17 +333,17 @@ } else if (id->dma_1word & 0x0001) { speed = XFER_SW_DMA_0; } else { - return ((int) ide_dma_off_quietly); - } + return 0; + } outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) aec6210_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 3) ? 0 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra) @@ -356,7 +356,7 @@ byte ultra66 = eighty_ninty_three(drive); if (drive->type != ATA_DISK) - return ((int) ide_dma_off_quietly); + return 0; if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) { speed = XFER_UDMA_4; @@ -381,17 +381,17 @@ } else if (id->dma_1word & 0x0001) { speed = XFER_SW_DMA_0; } else { - return ((int) ide_dma_off_quietly); + return 0; } outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) aec6260_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 3) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) @@ -403,7 +403,7 @@ case PCI_DEVICE_ID_ARTOP_ATP860R: return config_aec6260_chipset_for_dma(drive, ultra); default: - return ((int) ide_dma_off_quietly); + return 0; } } @@ -433,21 +433,23 @@ static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x001F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + on = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -455,62 +457,38 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: aec62xx_tune_drive(drive, 5); } - return drive->channel->udma(dma_func, drive, NULL); + udma_enable(drive, on, verbose); + return 0; } -/* - * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - */ -int aec62xx_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq) -{ - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_lostirq: - case ide_dma_timeout: - switch(drive->channel->pci_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: -// { -// int i = 0; -// byte reg49h = 0; -// pci_read_config_byte(drive->channel->pci_dev, 0x49, ®49h); -// for (i=0;i<256;i++) -// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h|0x10); -// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h & ~0x10); -// } -// return 0; - default: - break; - } - default: - break; - } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ +int aec62xx_dmaproc(struct ata_device *drive) +{ + return config_drive_xfer_rate(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_AEC62XX_TUNING */ +#endif +#endif unsigned int __init pci_init_aec62xx (struct pci_dev *dev) { @@ -546,7 +524,7 @@ hwif->speedproc = aec62xx_tune_chipset; # ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) - hwif->udma = aec62xx_dmaproc; + hwif->XXX_udma = aec62xx_dmaproc; hwif->highmem = 1; # else hwif->drives[0].autotune = 1; diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c --- a/drivers/ide/alim15x3.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/alim15x3.c Sun May 5 20:39:50 2002 @@ -297,7 +297,7 @@ pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0); } } - + pci_write_config_byte(dev, port, s_clc); pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); __restore_flags(flags); @@ -391,7 +391,7 @@ } else if (id->dma_1word & 0x0001) { speed = XFER_SW_DMA_0; } else { - return ((int) ide_dma_off_quietly); + return 0; } (void) ali15x3_tune_chipset(drive, speed); @@ -399,11 +399,11 @@ if (!drive->init_speed) drive->init_speed = speed; - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + rval = (int)( ((id->dma_ultra >> 11) & 3) ? 1: + ((id->dma_ultra >> 8) & 7) ? 1: + ((id->dma_mword >> 8) & 7) ? 1: + ((id->dma_1word >> 8) & 7) ? 1: + 0); return rval; } @@ -433,25 +433,29 @@ { struct hd_driveid *id = drive->id; struct ata_channel *hwif = drive->channel; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; byte can_ultra_dma = ali15x3_can_ultra(drive); - if ((m5229_revision<=0x20) && (drive->type != ATA_DISK)) - return hwif->udma(ide_dma_off_quietly, drive, NULL); + if ((m5229_revision<=0x20) && (drive->type != ATA_DISK)) { + udma_enable(drive, 0, 0); + return 0; + } if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); + on = config_chipset_for_dma(drive, can_ultra_dma); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -459,45 +463,47 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, can_ultra_dma); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, can_ultra_dma); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: config_chipset_for_pio(drive); } - return hwif->udma(dma_func, drive, NULL); + + udma_enable(drive, on, verbose); + + return 0; } -static int ali15x3_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int ali15x3_udma_write(struct ata_device *drive, struct request *rq) { - switch(func) { - case ide_dma_check: - return ali15x3_config_drive_for_dma(drive); - case ide_dma_write: - if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK)) - return 1; /* try PIO instead of DMA */ - break; - default: - break; - } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK)) + return 1; /* try PIO instead of DMA */ + + return ata_do_udma(0, drive, rq); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + +static int ali15x3_dmaproc(struct ata_device *drive) +{ + return ali15x3_config_drive_for_dma(drive); +} +#endif unsigned int __init pci_init_ali15x3(struct pci_dev *dev) { @@ -679,7 +685,8 @@ /* * M1543C or newer for DMAing */ - hwif->udma = ali15x3_dmaproc; + hwif->udma_write = ali15x3_udma_write; + hwif->XXX_udma = ali15x3_dmaproc; hwif->autodma = 1; } diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c --- a/drivers/ide/amd74xx.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/amd74xx.c Sun May 5 20:39:50 2002 @@ -275,36 +275,23 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA - -/* - * amd74xx_dmaproc() is a callback from upper layers that can do - * a lot, but we use it for DMA/PIO tuning only, delegating everything - * else to the default ide_dmaproc(). - */ - -int amd74xx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +int amd74xx_dmaproc(struct ata_device *drive) { + short w80 = drive->channel->udma_four; - if (func == ide_dma_check) { - - short w80 = drive->channel->udma_four; - - short speed = ata_timing_mode(drive, + short speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) | (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) | (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0)); - amd_set_drive(drive, speed); + amd_set_drive(drive, speed); - func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO) - ? ide_dma_on : ide_dma_off_quietly; - } + udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0); - return ide_dmaproc(func, drive, rq); + return 0; } - -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * The initialization callback. Here we determine the IDE chip type @@ -433,7 +420,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->highmem = 1; - hwif->udma = amd74xx_dmaproc; + hwif->XXX_udma = amd74xx_dmaproc; # ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; diff -Nru a/drivers/ide/ata-timing.h b/drivers/ide/ata-timing.h --- a/drivers/ide/ata-timing.h Sun May 5 20:39:50 2002 +++ b/drivers/ide/ata-timing.h Sun May 5 20:39:50 2002 @@ -74,12 +74,12 @@ * It's a bit elaborate due to the legacy we have to bear. */ -extern short ata_timing_mode(ide_drive_t *drive, int map); +extern short ata_timing_mode(struct ata_device *drive, int map); extern void ata_timing_quantize(struct ata_timing *t, struct ata_timing *q, int T, int UT); extern void ata_timing_merge(struct ata_timing *a, struct ata_timing *b, struct ata_timing *m, unsigned int what); extern struct ata_timing* ata_timing_data(short speed); -extern int ata_timing_compute(ide_drive_t *drive, +extern int ata_timing_compute(struct ata_device *drive, short speed, struct ata_timing *t, int T, int UT); #endif diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c --- a/drivers/ide/cmd64x.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/cmd64x.c Sun May 5 20:39:49 2002 @@ -208,10 +208,10 @@ * This routine writes the prepared setup/active/recovery counts * for a drive into the cmd646 chipset registers to active them. */ -static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) +static void program_drive_counts(struct ata_device *drive, int setup_count, int active_count, int recovery_count) { unsigned long flags; - ide_drive_t *drives = drive->channel->drives; + struct ata_device *drives = drive->channel->drives; byte temp_b; static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; static const byte recovery_counts[] = @@ -277,7 +277,7 @@ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. * Called with 255 at boot time. */ -static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted) +static void cmd64x_tuneproc(struct ata_device *drive, byte mode_wanted) { int recovery_time, clock_time; byte recovery_count2, cycle_count; @@ -351,7 +351,7 @@ } } -static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted) +static void cmd680_tuneproc(struct ata_device *drive, byte mode_wanted) { struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; @@ -381,7 +381,7 @@ pci_write_config_word(dev, drive_pci, speedt); } -static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed) +static void config_cmd64x_chipset_for_pio(struct ata_device *drive, byte set_speed) { byte speed = 0x00; byte set_pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; @@ -392,7 +392,7 @@ (void) ide_config_drive_speed(drive, speed); } -static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed) +static void config_cmd680_chipset_for_pio(struct ata_device *drive, byte set_speed) { struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; @@ -418,7 +418,7 @@ } } -static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +static void config_chipset_for_pio(struct ata_device *drive, byte set_speed) { if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680) { config_cmd680_chipset_for_pio(drive, set_speed); @@ -427,7 +427,7 @@ } } -static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed) +static int cmd64x_tune_chipset(struct ata_device *drive, byte speed) { #ifdef CONFIG_BLK_DEV_IDEDMA struct ata_channel *hwif = drive->channel; @@ -496,7 +496,7 @@ return err; } -static int cmd680_tune_chipset (ide_drive_t *drive, byte speed) +static int cmd680_tune_chipset(struct ata_device *drive, byte speed) { struct ata_channel *hwif = drive->channel; struct pci_dev *dev = hwif->pci_dev; @@ -612,7 +612,7 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +static int config_cmd64x_chipset_for_dma(struct ata_device *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; struct ata_channel *hwif = drive->channel; @@ -636,7 +636,7 @@ if (drive->type != ATA_DISK) { cmdprintk("CMD64X: drive is not a disk at double check, inital check failed!!\n"); - return ((int) ide_dma_off); + return 0; } /* UltraDMA only supported on PCI646U and PCI646U2, @@ -683,21 +683,21 @@ config_chipset_for_pio(drive, set_pio); if (set_pio) - return ((int) ide_dma_off_quietly); + return 0; if (cmd64x_tune_chipset(drive, speed)) - return ((int) ide_dma_off); + return 0; - rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + rval = (int)( ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); return rval; } -static int config_cmd680_chipset_for_dma (ide_drive_t *drive) +static int config_cmd680_chipset_for_dma(struct ata_device *drive) { struct hd_driveid *id = drive->id; byte udma_66 = eighty_ninty_three(drive); @@ -725,28 +725,28 @@ config_chipset_for_pio(drive, set_pio); if (set_pio) - return ((int) ide_dma_off_quietly); + return 0; if (cmd680_tune_chipset(drive, speed)) - return ((int) ide_dma_off); + return 0; - rval = (int)( ((id->dma_ultra >> 14) & 3) ? ide_dma_on : - ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + rval = (int)( ((id->dma_ultra >> 14) & 3) ? 1 : + ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); return rval; } -static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +static int config_chipset_for_dma(struct ata_device *drive, unsigned int rev, byte ultra_66) { if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680) return (config_cmd680_chipset_for_dma(drive)); return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66)); } -static int cmd64x_config_drive_for_dma (ide_drive_t *drive) +static int cmd64x_config_drive_for_dma(struct ata_device *drive) { struct hd_driveid *id = drive->id; struct ata_channel *hwif = drive->channel; @@ -756,7 +756,8 @@ byte can_ultra_66 = 0; byte can_ultra_100 = 0; byte can_ultra_133 = 0; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; @@ -777,23 +778,26 @@ can_ultra_100 = 0; break; default: - return hwif->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); + + return 0; } if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma && (drive->type == ATA_DISK)) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if ((id->field_valid & 4) && (can_ultra_33)) { if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66); + on = config_chipset_for_dma(drive, class_rev, can_ultra_66); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -801,161 +805,158 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, class_rev, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, class_rev, 0); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, class_rev, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, class_rev, 0); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: config_chipset_for_pio(drive, 1); } - return drive->channel->udma(dma_func, drive, NULL); + + udma_enable(drive, on, verbose); + + return 0; } -static int cmd680_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int cmd680_dmaproc(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - return cmd64x_config_drive_for_dma(drive); - default: - break; - } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive, rq); + return cmd64x_config_drive_for_dma(drive); } -static int cmd64x_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int cmd64x_udma_stop(struct ata_device *drive) { - byte dma_stat = 0; - byte dma_alt_stat = 0; - byte mask = (drive->channel->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - unsigned long dma_base = drive->channel->dma_base; - struct pci_dev *dev = drive->channel->pci_dev; - byte jack_slap = ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0; - - switch (func) { - case ide_dma_check: - return cmd64x_config_drive_for_dma(drive); - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - if (jack_slap) { - byte dma_intr = 0; - byte dma_mask = (drive->channel->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - byte dma_reg = (drive->channel->unit) ? ARTTIM2 : CFR; - (void) pci_read_config_byte(dev, dma_reg, &dma_intr); - /* - * DAMN BMIDE is not connected to PCI space! - * Have to manually jack-slap that bitch! - * To allow the PCI side to read incoming interrupts. - */ - (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); /* clear the INTR bit */ - } - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4; /* verify good DMA status */ - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); + struct ata_channel *ch = drive->channel; + u8 dma_stat = 0; + unsigned long dma_base = ch->dma_base; + struct pci_dev *dev = ch->pci_dev; + u8 jack_slap = ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0; + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + if (jack_slap) { + byte dma_intr = 0; + byte dma_mask = (ch->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; + byte dma_reg = (ch->unit) ? ARTTIM2 : CFR; + (void) pci_read_config_byte(dev, dma_reg, &dma_intr); + /* + * DAMN BMIDE is not connected to PCI space! + * Have to manually jack-slap that bitch! + * To allow the PCI side to read incoming interrupts. + */ + (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); /* clear the INTR bit */ + } + udma_destroy_table(ch); /* purge DMA mappings */ + return (dma_stat & 7) != 4; /* verify good DMA status */ +} + +static int cmd64x_udma_irq_status(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + u8 dma_stat = 0; + u8 dma_alt_stat = 0; + unsigned long dma_base = ch->dma_base; + struct pci_dev *dev = ch->pci_dev; + u8 mask = (ch->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; + + dma_stat = inb(dma_base+2); + (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); #ifdef DEBUG - printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask); + printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask); #endif - if (!(dma_alt_stat & mask)) { - return 0; - } - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ - default: - break; + if (!(dma_alt_stat & mask)) { + return 0; } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive, rq); + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ +} + +static int cmd64x_dmaproc(struct ata_device *drive) +{ + return cmd64x_config_drive_for_dma(drive); +} + +static int cmd646_1_udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + drive->waiting_for_dma = 0; + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* and free any DMA resources */ + return (dma_stat & 7) != 4; /* verify good DMA status */ } /* * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old * event order for DMA transfers. */ -static int cmd646_1_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int cmd646_1_dmaproc(struct ata_device *drive) { - struct ata_channel *hwif = drive->channel; - unsigned long dma_base = hwif->dma_base; - byte dma_stat; - - switch (func) { - case ide_dma_check: - return cmd64x_config_drive_for_dma(drive); - case ide_dma_end: - drive->waiting_for_dma = 0; - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* and free any DMA resources */ - return (dma_stat & 7) != 4; /* verify good DMA status */ - default: - break; - } - - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive, rq); + return cmd64x_config_drive_for_dma(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif -static int cmd680_busproc (ide_drive_t * drive, int state) +static int cmd680_busproc(struct ata_device * drive, int state) { #if 0 - struct ata_channel *hwif = drive->channel; - u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0; + struct ata_channel *ch = drive->channel; + u8 addr_mask = (ch->unit) ? 0xB0 : 0xA0; u32 stat_config = 0; - pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config); + pci_read_config_dword(ch->pci_dev, addr_mask, &stat_config); - if (!hwif) + if (!ch) return -EINVAL; switch (state) { case BUSSTATE_ON: - hwif->drives[0].failures = 0; - hwif->drives[1].failures = 0; + ch->drives[0].failures = 0; + ch->drives[1].failures = 0; break; case BUSSTATE_OFF: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + ch->drives[0].failures = ch->drives[0].max_failures + 1; + ch->drives[1].failures = ch->drives[1].max_failures + 1; break; case BUSSTATE_TRISTATE: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + ch->drives[0].failures = ch->drives[0].max_failures + 1; + ch->drives[1].failures = ch->drives[1].max_failures + 1; break; default: return 0; } - hwif->bus_state = state; + ch->bus_state = state; #endif return 0; } -static void cmd680_reset (ide_drive_t *drive) +static void cmd680_reset(struct ata_device *drive) { #if 0 - struct ata_channel *hwif = drive->channel; - u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0; - byte reset = 0; + struct ata_channel *ch = drive->channel; + u8 addr_mask = (ch->unit) ? 0xB0 : 0xA0; + u8 reset = 0; - pci_read_config_byte(hwif->pci_dev, addr_mask, &reset); - pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03); + pci_read_config_byte(ch->pci_dev, addr_mask, &reset); + pci_write_config_byte(ch->pci_dev, addr_mask, reset|0x03); #endif } @@ -1124,28 +1125,33 @@ #ifdef CONFIG_BLK_DEV_IDEDMA switch(dev->device) { case PCI_DEVICE_ID_CMD_680: - hwif->busproc = &cmd680_busproc; - hwif->udma = &cmd680_dmaproc; - hwif->resetproc = &cmd680_reset; - hwif->speedproc = &cmd680_tune_chipset; - hwif->tuneproc = &cmd680_tuneproc; + hwif->busproc = cmd680_busproc; + hwif->XXX_udma = cmd680_dmaproc; + hwif->resetproc = cmd680_reset; + hwif->speedproc = cmd680_tune_chipset; + hwif->tuneproc = cmd680_tuneproc; break; case PCI_DEVICE_ID_CMD_649: case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_643: - hwif->udma = &cmd64x_dmaproc; - hwif->tuneproc = &cmd64x_tuneproc; - hwif->speedproc = &cmd64x_tune_chipset; + hwif->udma_stop = cmd64x_udma_stop; + hwif->udma_irq_status = cmd64x_udma_irq_status; + hwif->XXX_udma = cmd64x_dmaproc; + hwif->tuneproc = cmd64x_tuneproc; + hwif->speedproc = cmd64x_tune_chipset; break; case PCI_DEVICE_ID_CMD_646: hwif->chipset = ide_cmd646; if (class_rev == 0x01) { - hwif->udma = &cmd646_1_dmaproc; + hwif->udma_stop = cmd646_1_udma_stop; + hwif->XXX_udma = cmd646_1_dmaproc; } else { - hwif->udma = &cmd64x_dmaproc; + hwif->udma_stop = cmd64x_udma_stop; + hwif->udma_irq_status = cmd64x_udma_irq_status; + hwif->XXX_udma = cmd64x_dmaproc; } - hwif->tuneproc = &cmd64x_tuneproc; - hwif->speedproc = &cmd64x_tune_chipset; + hwif->tuneproc = cmd64x_tuneproc; + hwif->speedproc = cmd64x_tune_chipset; break; default: break; diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c --- a/drivers/ide/cs5530.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/cs5530.c Sun May 5 20:39:50 2002 @@ -144,7 +144,7 @@ /* * Default to DMA-off in case we run into trouble here. */ - hwif->udma(ide_dma_off_quietly, drive, NULL); + udma_enable(drive, 0, 0); outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ /* @@ -158,7 +158,7 @@ */ if (mate->present) { struct hd_driveid *mateid = mate->id; - if (mateid && (mateid->capability & 1) && !hwif->udma(ide_dma_bad_drive, mate, NULL)) { + if (mateid && (mateid->capability & 1) && !udma_black_list(mate)) { if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) udma_ok = 1; else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) @@ -172,7 +172,7 @@ * Now see what the current drive is capable of, * selecting UDMA only if the mate said it was ok. */ - if (id && (id->capability & 1) && hwif->autodma && !hwif->udma(ide_dma_bad_drive, drive, NULL)) { + if (id && (id->capability & 1) && hwif->autodma && !udma_black_list(drive)) { if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { if (id->dma_ultra & 4) mode = XFER_UDMA_2; @@ -229,26 +229,16 @@ /* * Finally, turn DMA on in software, and exit. */ - return hwif->udma(ide_dma_on, drive, NULL); /* success */ + udma_enable(drive, 1, 1); /* success */ + + return 0; } -/* - * This is a CS5530-specific wrapper for the standard ide_dmaproc(). - * We need it for our custom "ide_dma_check" function. - * All other requests are forwarded to the standard ide_dmaproc(). - */ -int cs5530_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +int cs5530_dmaproc(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - return cs5530_config_dma(drive); - default: - break; - } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive, rq); + return cs5530_config_dma(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * Initialize the cs5530 bridge for reliable IDE DMA operation. @@ -353,11 +343,11 @@ unsigned int basereg, d0_timings; #ifdef CONFIG_BLK_DEV_IDEDMA - hwif->udma = cs5530_dmaproc; + hwif->XXX_udma = cs5530_dmaproc; hwif->highmem = 1; #else hwif->autodma = 0; -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif hwif->tuneproc = &cs5530_tuneproc; basereg = CS5530_BASEREG(hwif); diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c --- a/drivers/ide/cy82c693.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/cy82c693.c Sun May 5 20:39:49 2002 @@ -8,7 +8,7 @@ * * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. * Writting the driver was quite simple, since most of the job is - * done by the generic pci-ide support. + * done by the generic pci-ide support. * The hard part was finding the CY82C693's datasheet on Cypress's * web page :-(. But Altavista solved this problem :-). * @@ -17,12 +17,12 @@ * - I recently got a 16.8G IBM DTTA, so I was able to test it with * a large and fast disk - the results look great, so I'd say the * driver is working fine :-) - * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA - * - this is my first linux driver, so there's probably a lot of room + * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA + * - this is my first linux driver, so there's probably a lot of room * for optimizations and bug fixing, so feel free to do it. * - use idebus=xx parameter to set PCI bus speed - needed to calc * timings for PIO modes (default will be 40) - * - if using PIO mode it's a good idea to set the PIO mode and + * - if using PIO mode it's a good idea to set the PIO mode and * 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda * - I had some problems with my IBM DHEA with PIO modes < 2 * (lost interrupts) ????? @@ -71,7 +71,7 @@ * note: the value for busmaster timeout is tricky and i got it by trial and error ! * using a to low value will cause DMA timeouts and drop IDE performance * using a to high value will cause audio playback to scatter - * if you know a better value or how to calc it, please let me know + * if you know a better value or how to calc it, please let me know */ #define BUSMASTER_TIMEOUT 0x50 /* twice the value written in cy82c693ub datasheet */ /* @@ -81,12 +81,12 @@ /* here are the offset definitions for the registers */ #define CY82_IDE_CMDREG 0x04 #define CY82_IDE_ADDRSETUP 0x48 -#define CY82_IDE_MASTER_IOR 0x4C -#define CY82_IDE_MASTER_IOW 0x4D -#define CY82_IDE_SLAVE_IOR 0x4E +#define CY82_IDE_MASTER_IOR 0x4C +#define CY82_IDE_MASTER_IOW 0x4D +#define CY82_IDE_SLAVE_IOR 0x4E #define CY82_IDE_SLAVE_IOW 0x4F -#define CY82_IDE_MASTER_8BIT 0x50 -#define CY82_IDE_SLAVE_8BIT 0x51 +#define CY82_IDE_MASTER_8BIT 0x50 +#define CY82_IDE_SLAVE_8BIT 0x51 #define CY82_INDEX_PORT 0x22 #define CY82_DATA_PORT 0x23 @@ -188,14 +188,14 @@ if (mode>2) /* make sure we set a valid mode */ mode = 2; - + if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */ mode = drive->id->tDMA; - + index = (drive->channel->unit == 0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; #if CY82C693_DEBUG_LOGS - /* for debug let's show the previous values */ + /* for debug let's show the previous values */ OUT_BYTE(index, CY82_INDEX_PORT); data = IN_BYTE(CY82_DATA_PORT); @@ -212,7 +212,7 @@ printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, mode, single); #endif /* CY82C693_DEBUG_INFO */ - /* + /* * note: below we set the value for Bus Master IDE TimeOut Register * I'm not absolutly sure what this does, but it solved my problem * with IDE DMA and sound, so I now can play sound and work with @@ -226,45 +226,44 @@ OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); OUT_BYTE(data, CY82_DATA_PORT); -#if CY82C693_DEBUG_INFO +#if CY82C693_DEBUG_INFO printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data); #endif /* CY82C693_DEBUG_INFO */ } -/* +/* * used to set DMA mode for CY82C693 (single and multi modes) */ -static int cy82c693_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int cy82c693_dmaproc(struct ata_device *drive) { /* - * if the function is dma on, set dma mode for drive everything - * else is done by the defaul func + * Set dma mode for drive everything else is done by the defaul func. */ - if (func == ide_dma_on) { - struct hd_driveid *id = drive->id; + struct hd_driveid *id = drive->id; #if CY82C693_DEBUG_INFO - printk (KERN_INFO "dma_on: %s\n", drive->name); -#endif /* CY82C693_DEBUG_INFO */ + printk (KERN_INFO "dma_on: %s\n", drive->name); +#endif - if (id != NULL) { - /* Enable DMA on any drive that has DMA (multi or single) enabled */ - if (id->field_valid & 2) { /* regular DMA */ - int mmode, smode; - - mmode = id->dma_mword & (id->dma_mword >> 8); - smode = id->dma_1word & (id->dma_1word >> 8); - - if (mmode != 0) - cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */ - else if (smode != 0) - cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */ - } + if (id != NULL) { + /* Enable DMA on any drive that has DMA (multi or single) enabled */ + if (id->field_valid & 2) { /* regular DMA */ + int mmode, smode; + + mmode = id->dma_mword & (id->dma_mword >> 8); + smode = id->dma_1word & (id->dma_1word >> 8); + + if (mmode != 0) + cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */ + else if (smode != 0) + cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */ } } - return ide_dmaproc(func, drive, rq); + udma_enable(drive, 1, 1); + + return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * tune ide drive - set PIO mode @@ -287,14 +286,14 @@ #if CY82C693_DEBUG_LOGS /* for debug let's show the register values */ - - if (drive->select.b.unit == 0) { + + if (drive->select.b.unit == 0) { /* - * get master drive registers + * get master drive registers * address setup control register * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); addrCtrl &= 0x0F; /* now let's get the remaining registers */ @@ -306,7 +305,7 @@ * set slave drive registers * address setup control register * is 32 bit !!! - */ + */ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); addrCtrl &= 0xF0; @@ -336,9 +335,9 @@ * set master drive * address setup control register * is 32 bit !!! - */ + */ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - + addrCtrl &= (~0xF); addrCtrl |= (unsigned int)pclk.address_time; pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); @@ -347,14 +346,14 @@ pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r); pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w); pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8); - + addrCtrl &= 0xF; } else { /* * set slave drive * address setup control register * is 32 bit !!! - */ + */ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); addrCtrl &= (~0xF0); @@ -368,7 +367,7 @@ addrCtrl >>= 4; addrCtrl &= 0xF; - } + } #if CY82C693_DEBUG_INFO printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); @@ -388,14 +387,14 @@ { #ifdef CY82C693_SETDMA_CLOCK byte data; -#endif /* CY82C693_SETDMA_CLOCK */ +#endif /* CY82C693_SETDMA_CLOCK */ /* write info about this verion of the driver */ printk (KERN_INFO CY82_VERSION "\n"); #ifdef CY82C693_SETDMA_CLOCK /* okay let's set the DMA clock speed */ - + OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT); data = IN_BYTE(CY82_DATA_PORT); @@ -406,11 +405,11 @@ /* * for some reason sometimes the DMA controller * speed is set to ATCLK/2 ???? - we fix this here - * + * * note: i don't know what causes this strange behaviour, * but even changing the dma speed doesn't solve it :-( - * the ide performance is still only half the normal speed - * + * the ide performance is still only half the normal speed + * * if anybody knows what goes wrong with my machine, please * let me know - ASK */ @@ -442,7 +441,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->highmem = 1; - hwif->udma = cy82c693_dmaproc; + hwif->XXX_udma = cy82c693_dmaproc; if (!noautodma) hwif->autodma = 1; } diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c --- a/drivers/ide/hpt34x.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/hpt34x.c Sun May 5 20:39:49 2002 @@ -210,7 +210,7 @@ byte speed = 0x00; if (drive->type != ATA_DISK) - return ((int) ide_dma_off_quietly); + return 0; hpt34x_clear_chipset(drive); @@ -237,36 +237,38 @@ } else if (id->dma_1word & 0x0001) { speed = XFER_SW_DMA_0; } else { - return ((int) ide_dma_off_quietly); + return 0; } (void) hpt34x_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 3) ? 0 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } -static int config_drive_xfer_rate (ide_drive_t *drive) +static int config_drive_xfer_rate(struct ata_device *drive) { struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x0007) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + on = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -274,82 +276,97 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: config_chipset_for_pio(drive); } #ifndef CONFIG_HPT34X_AUTODMA - if (dma_func == ide_dma_on) - dma_func = ide_dma_off; -#endif /* CONFIG_HPT34X_AUTODMA */ + if (on) + on = 0; +#endif + udma_enable(drive, on, verbose); - return drive->channel->dmaproc(dma_func, drive); + return 0; +} + +static int hpt34x_udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* purge DMA mappings */ + + return (dma_stat & 7) != 4; /* verify good DMA status */ +} + +static int do_udma(unsigned int reading, struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + unsigned int count; + + if (!(count = udma_new_table(ch, rq))) + return 1; /* try PIO instead of DMA */ + + outl(ch->dmatable_dma, dma_base + 4); /* PRD table */ + reading |= 0x01; + outb(reading, dma_base); /* specify r/w */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; + + if (drive->type != ATA_DISK) + return 0; + + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ + OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + + return 0; +} + +static int hpt34x_udma_read(struct ata_device *drive, struct request *rq) +{ + return do_udma(1 << 3, drive, rq); +} + +static int hpt34x_udma_write(struct ata_device *drive, struct request *rq) +{ + return do_udma(0, drive, rq); } /* - * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - * * This is specific to the HPT343 UDMA bios-less chipset * and HPT345 UDMA bios chipset (stamped HPT363) * by HighPoint|Triones Technologies, Inc. */ - -int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +static int hpt34x_dmaproc(struct ata_device *drive) { - struct ata_channel *hwif = drive->channel; - unsigned long dma_base = hwif->dma_base; - unsigned int count, reading = 0; - byte dma_stat; - - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_read: - reading = 1 << 3; - case ide_dma_write: - if (!(count = ide_build_dmatable(drive, func))) - return 1; /* try PIO instead of DMA */ - outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ - reading |= 0x01; - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ - drive->waiting_for_dma = 1; - if (drive->type != ATA_DISK) - return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ - OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - return 0; - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4; /* verify good DMA status */ - default: - break; - } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ + return config_drive_xfer_rate(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * If the BIOS does not set the IO base addaress to XX00, 343 will fail. @@ -423,7 +440,10 @@ else hwif->autodma = 0; - hwif->dmaproc = &hpt34x_dmaproc; + hwif->udma_stop = hpt34x_udma_stop; + hwif->udma_read = hpt34x_udma_read; + hwif->udma_write = hpt34x_udma_write; + hwif->XXX_udma = hpt34x_dmaproc; hwif->highmem = 1; } else { hwif->drives[0].autotune = 1; diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c --- a/drivers/ide/hpt366.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/hpt366.c Sun May 5 20:39:49 2002 @@ -346,8 +346,6 @@ static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev); static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev); byte hpt366_proc = 0; -byte hpt363_shared_irq; -byte hpt363_shared_pin; extern char *ide_xfer_verbose (byte xfer_rate); #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) @@ -663,7 +661,7 @@ int rval; if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0)) - return ((int) ide_dma_off_quietly); + return 0; if ((id->dma_ultra & 0x0020) && (!check_in_drive_lists(drive, bad_ata100_5)) && @@ -696,15 +694,15 @@ } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; } else { - return ((int) ide_dma_off_quietly); + return 0; } (void) hpt3xx_tune_chipset(drive, speed); - rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + rval = (int)( ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + 0); return rval; } @@ -746,146 +744,165 @@ static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive); + on = config_chipset_for_dma(drive); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { try_dma_modes: if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: config_chipset_for_pio(drive); } - return drive->channel->udma(dma_func, drive, NULL); + udma_enable(drive, on, verbose); + + return 0; +} + +static void hpt366_udma_irq_lost(struct ata_device *drive) +{ + u8 reg50h = 0, reg52h = 0, reg5ah = 0; + + pci_read_config_byte(drive->channel->pci_dev, 0x50, ®50h); + pci_read_config_byte(drive->channel->pci_dev, 0x52, ®52h); + pci_read_config_byte(drive->channel->pci_dev, 0x5a, ®5ah); + printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", + drive->name, __FUNCTION__, reg50h, reg52h, reg5ah); + if (reg5ah & 0x10) + pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10); } /* - * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - * * This is specific to the HPT366 UDMA bios chipset * by HighPoint|Triones Technologies, Inc. */ -int hpt366_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int hpt366_dmaproc(struct ata_device *drive) { - byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0; - unsigned long dma_base = drive->channel->dma_base; + return config_drive_xfer_rate(drive); +} - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ - case ide_dma_lostirq: - pci_read_config_byte(drive->channel->pci_dev, 0x50, ®50h); - pci_read_config_byte(drive->channel->pci_dev, 0x52, ®52h); - pci_read_config_byte(drive->channel->pci_dev, 0x5a, ®5ah); - printk("%s: (ide_dma_lostirq) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", - drive->name, reg50h, reg52h, reg5ah); - if (reg5ah & 0x10) - pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10); - /* fall through to a reset */ -#if 0 - case ide_dma_begin: - case ide_dma_end: - /* reset the chips state over and over.. */ - pci_write_config_byte(drive->channel->pci_dev, 0x51, 0x13); -#endif - break; - case ide_dma_timeout: - default: - break; - } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ +static void do_udma_start(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + + u8 regstate = ch->unit ? 0x54 : 0x50; + pci_write_config_byte(ch->pci_dev, regstate, 0x37); + udelay(10); } -int hpt370_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int hpt370_udma_start(struct ata_device *drive, struct request *__rq) { - struct ata_channel *hwif = drive->channel; - unsigned long dma_base = hwif->dma_base; - byte regstate = hwif->unit ? 0x54 : 0x50; - byte reginfo = hwif->unit ? 0x56 : 0x52; - byte dma_stat; - - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ - - case ide_dma_end: - dma_stat = inb(dma_base + 2); - if (dma_stat & 0x01) { - udelay(20); /* wait a little */ - dma_stat = inb(dma_base + 2); - } - if ((dma_stat & 0x01) == 0) - break; + struct ata_channel *ch = drive->channel; - func = ide_dma_timeout; - /* fallthrough */ + do_udma_start(drive); - case ide_dma_timeout: - case ide_dma_lostirq: - pci_read_config_byte(hwif->pci_dev, reginfo, - &dma_stat); - printk("%s: %d bytes in FIFO\n", drive->name, - dma_stat); - pci_write_config_byte(hwif->pci_dev, regstate, 0x37); - udelay(10); - dma_stat = inb(dma_base); - outb(dma_stat & ~0x1, dma_base); /* stop dma */ - dma_stat = inb(dma_base + 2); - outb(dma_stat | 0x6, dma_base+2); /* clear errors */ - /* fallthrough */ + /* Note that this is done *after* the cmd has been issued to the drive, + * as per the BM-IDE spec. The Promise Ultra33 doesn't work correctly + * when we do this part before issuing the drive cmd. + */ -#ifdef HPT_RESET_STATE_ENGINE - case ide_dma_begin: -#endif - pci_write_config_byte(hwif->pci_dev, regstate, 0x37); - udelay(10); - break; + outb(inb(ch->dma_base) | 1, ch->dma_base); /* start DMA */ - default: - break; + return 0; +} + +static void do_timeout_irq(struct ata_device *drive) +{ + u8 dma_stat; + u8 regstate = drive->channel->unit ? 0x54 : 0x50; + u8 reginfo = drive->channel->unit ? 0x56 : 0x52; + unsigned long dma_base = drive->channel->dma_base; + + pci_read_config_byte(drive->channel->pci_dev, reginfo, &dma_stat); + printk(KERN_INFO "%s: %d bytes in FIFO\n", drive->name, dma_stat); + pci_write_config_byte(drive->channel->pci_dev, regstate, 0x37); + udelay(10); + dma_stat = inb(dma_base); + outb(dma_stat & ~0x1, dma_base); /* stop dma */ + dma_stat = inb(dma_base + 2); + outb(dma_stat | 0x6, dma_base+2); /* clear errors */ + +} + +static void hpt370_udma_timeout(struct ata_device *drive) +{ + do_timeout_irq(drive); + do_udma_start(drive); +} + +static void hpt370_udma_irq_lost(struct ata_device *drive) +{ + do_timeout_irq(drive); + do_udma_start(drive); +} + +static int hpt370_udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + dma_stat = inb(dma_base + 2); + if (dma_stat & 0x01) { + udelay(20); /* wait a little */ + dma_stat = inb(dma_base + 2); + } + if ((dma_stat & 0x01) != 0) { + do_timeout_irq(drive); + do_udma_start(drive); } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* purge DMA mappings */ + + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ +} + + +static int hpt370_dmaproc(struct ata_device *drive) +{ + return config_drive_xfer_rate(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * Since SUN Cobalt is attempting to do this operation, I should disclose @@ -1185,9 +1202,14 @@ pci_read_config_byte(hwif->pci_dev, 0x5a, ®5ah); if (reg5ah & 0x10) /* interrupt force enable */ pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10); - hwif->udma = hpt370_dmaproc; + hwif->udma_start = hpt370_udma_start; + hwif->udma_stop = hpt370_udma_stop; + hwif->udma_timeout = hpt370_udma_timeout; + hwif->udma_irq_lost = hpt370_udma_irq_lost; + hwif->XXX_udma = hpt370_dmaproc; } else { - hwif->udma = hpt366_dmaproc; + hwif->udma_irq_lost = hpt366_udma_irq_lost; + hwif->XXX_udma = hpt366_dmaproc; } if (!noautodma) hwif->autodma = 1; diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c --- a/drivers/ide/icside.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/icside.c Sun May 5 20:39:49 2002 @@ -242,9 +242,9 @@ } static int -icside_build_dmatable(ide_drive_t *drive, int reading) +icside_udma_new_table(struct ata_channel *ch, struct request *rq) { - return drive->channel->sg_nents = ide_build_sglist(drive->channel, HWGROUP(drive)->rq); + return ch->sg_nents = ide_build_sglist(ch, rq); } /* Teardown mappings after DMA has completed. */ @@ -332,7 +332,7 @@ int i; byte stat, dma_stat; - dma_stat = drive->channel->dmaproc(ide_dma_end, drive); + dma_stat = drive->channel->udma(ide_dma_end, drive, rq); stat = GET_STAT(); /* get drive status */ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { if (!dma_stat) { @@ -350,7 +350,7 @@ static int -icside_dma_check(ide_drive_t *drive) +icside_dma_check(struct ata_device *drive, struct request *rq) { struct hd_driveid *id = drive->id; struct ata_channel *hwif = drive->channel; @@ -381,14 +381,7 @@ out: func = icside_config_if(drive, xfer_mode); - return hwif->dmaproc(func, drive); -} - -static int -icside_dma_verbose(ide_drive_t *drive) -{ - printk(", DMA"); - return 1; + return hwif->udma(func, drive, rq); } static int @@ -413,12 +406,12 @@ return 0; case ide_dma_check: - return icside_dma_check(drive); + return icside_dma_check(drive, rq); case ide_dma_read: reading = 1; case ide_dma_write: - count = icside_build_dmatable(drive, reading); + count = icside_udma_new_table(hwif, rq); if (!count) return 1; disable_dma(hwif->hw.dma); @@ -457,9 +450,6 @@ case ide_dma_test_irq: return inb((unsigned long)hwif->hw.priv) & 1; - - case ide_dma_verbose: - return icside_dma_verbose(drive); case ide_dma_timeout: default: diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-cd.c Sun May 5 20:39:49 2002 @@ -737,9 +737,9 @@ if (info->dma) { if (info->cmd == READ) - info->dma = !drive->channel->udma(ide_dma_read, drive, rq); + info->dma = !udma_read(drive, rq); else if (info->cmd == WRITE) - info->dma = !drive->channel->udma(ide_dma_write, drive, rq); + info->dma = !udma_write(drive, rq); else printk("ide-cd: DMA set, but not allowed\n"); } @@ -755,7 +755,7 @@ OUT_BYTE (drive->ctl, IDE_CONTROL_REG); if (info->dma) - drive->channel->udma(ide_dma_begin, drive, NULL); + udma_start(drive, rq); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { ide_set_handler(drive, handler, WAIT_CMD, cdrom_timer_expiry); @@ -905,8 +905,8 @@ /* Check for errors. */ if (dma) { info->dma = 0; - if ((dma_error = drive->channel->udma(ide_dma_end, drive, NULL))) - drive->channel->udma(ide_dma_off, drive, NULL); + if ((dma_error = udma_stop(drive))) + udma_enable(drive, 0, 1); } if (cdrom_decode_status(&startstop, drive, rq, 0, &stat)) @@ -1480,9 +1480,9 @@ /* Check for errors. */ if (dma) { info->dma = 0; - if ((dma_error = drive->channel->udma(ide_dma_end, drive, NULL))) { + if ((dma_error = udma_stop(drive))) { printk("ide-cd: write dma error\n"); - drive->channel->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); } } @@ -2652,7 +2652,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) - (void) drive->channel->udma(ide_dma_verbose, drive, NULL); + udma_print(drive); #endif printk("\n"); diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-disk.c Sun May 5 20:39:49 2002 @@ -1,11 +1,12 @@ -/* - * Copyright (C) 1994-1998 Linus Torvalds and authors: +/***** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 1994-1998,2002 Linus Torvalds and authors: * - * Mark Lord - * Gadi Oxman - * Andre Hedrick - * Jens Axboe - * Marcin Dalecki + * Mark Lord + * Gadi Oxman + * Andre Hedrick + * Jens Axboe + * Marcin Dalecki * * This is the ATA disk device driver, as evolved from hd.c and ide.c. */ @@ -88,7 +89,7 @@ return 0; /* lba_capacity value may be bad */ } -static u8 get_command(ide_drive_t *drive, int cmd) +static u8 get_command(struct ata_device *drive, int cmd) { int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; @@ -98,6 +99,8 @@ if (lba48bit) { if (cmd == READ) { + if (drive->using_tcq) + return WIN_READDMA_QUEUED_EXT; if (drive->using_dma) return WIN_READDMA_EXT; else if (drive->mult_count) @@ -105,6 +108,8 @@ else return WIN_READ_EXT; } else if (cmd == WRITE) { + if (drive->using_tcq) + return WIN_WRITEDMA_QUEUED_EXT; if (drive->using_dma) return WIN_WRITEDMA_EXT; else if (drive->mult_count) @@ -114,6 +119,8 @@ } } else { if (cmd == READ) { + if (drive->using_tcq) + return WIN_READDMA_QUEUED; if (drive->using_dma) return WIN_READDMA; else if (drive->mult_count) @@ -121,6 +128,8 @@ else return WIN_READ; } else if (cmd == WRITE) { + if (drive->using_tcq) + return WIN_WRITEDMA_QUEUED; if (drive->using_dma) return WIN_WRITEDMA; else if (drive->mult_count) @@ -148,7 +157,11 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.taskfile.sector_count = rq->tag << 3; + } else + args.taskfile.sector_count = sectors; args.taskfile.sector_number = sect; args.taskfile.low_cylinder = cyl; @@ -184,7 +197,12 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.taskfile.sector_count = rq->tag << 3; + } else + args.taskfile.sector_count = sectors; + args.taskfile.sector_number = block; args.taskfile.low_cylinder = (block >>= 8); @@ -226,8 +244,14 @@ memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = sectors; - args.hobfile.sector_count = sectors >> 8; + if (blk_rq_tagged(rq)) { + args.taskfile.feature = sectors; + args.hobfile.feature = sectors >> 8; + args.taskfile.sector_count = rq->tag << 3; + } else { + args.taskfile.sector_count = sectors; + args.hobfile.sector_count = sectors >> 8; + } args.taskfile.sector_number = block; /* low lba */ args.taskfile.low_cylinder = (block >>= 8); /* mid lba */ @@ -285,6 +309,30 @@ return promise_rw_disk(drive, rq, block); } + /* + * start a tagged operation + */ + if (drive->using_tcq) { + unsigned long flags; + int ret; + + spin_lock_irqsave(&ide_lock, flags); + + ret = blk_queue_start_tag(&drive->queue, rq); + + if (ata_pending_commands(drive) > drive->max_depth) + drive->max_depth = ata_pending_commands(drive); + if (ata_pending_commands(drive) > drive->max_last_depth) + drive->max_last_depth = ata_pending_commands(drive); + + spin_unlock_irqrestore(&ide_lock, flags); + + if (ret) { + BUG_ON(!ata_pending_commands(drive)); + return ide_started; + } + } + /* 48-bit LBA */ if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) return lba48_do_request(drive, rq, block); @@ -297,7 +345,7 @@ return chs_do_request(drive, rq, block); } -static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive) +static int idedisk_open (struct inode *inode, struct file *filp, struct ata_device *drive) { MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { @@ -322,7 +370,7 @@ return 0; } -static int idedisk_flushcache(ide_drive_t *drive) +static int idedisk_flushcache(struct ata_device *drive) { struct ata_taskfile args; @@ -338,7 +386,7 @@ return ide_raw_taskfile(drive, &args, NULL); } -static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) +static void idedisk_release (struct inode *inode, struct file *filp, struct ata_device *drive) { if (drive->removable && !drive->usage) { struct ata_taskfile args; @@ -360,7 +408,7 @@ MOD_DEC_USE_COUNT; } -static int idedisk_check_media_change (ide_drive_t *drive) +static int idedisk_check_media_change(struct ata_device *drive) { /* if removable, always assume it was changed */ return drive->removable; @@ -426,7 +474,7 @@ return IS_PDC4030_DRIVE ? ide_stopped : ide_started; } -static void idedisk_pre_reset (ide_drive_t *drive) +static void idedisk_pre_reset(struct ata_device *drive) { int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1; @@ -442,7 +490,7 @@ #ifdef CONFIG_PROC_FS -static int smart_enable(ide_drive_t *drive) +static int smart_enable(struct ata_device *drive) { struct ata_taskfile args; @@ -456,7 +504,7 @@ return ide_raw_taskfile(drive, &args, NULL); } -static int get_smart_values(ide_drive_t *drive, u8 *buf) +static int get_smart_values(struct ata_device *drive, u8 *buf) { struct ata_taskfile args; @@ -473,7 +521,7 @@ return ide_raw_taskfile(drive, &args, buf); } -static int get_smart_thresholds(ide_drive_t *drive, u8 *buf) +static int get_smart_thresholds(struct ata_device *drive, u8 *buf) { struct ata_taskfile args; @@ -493,7 +541,7 @@ static int proc_idedisk_read_cache (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + struct ata_device *drive = (struct ata_device *) data; char *out = page; int len; @@ -507,7 +555,7 @@ static int proc_idedisk_read_smart_thresholds (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + struct ata_device *drive = (struct ata_device *)data; int len = 0, i = 0; if (!get_smart_thresholds(drive, page)) { @@ -526,8 +574,8 @@ static int proc_idedisk_read_smart_values (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; - int len = 0, i = 0; + struct ata_device *drive = (struct ata_device *)data; + int len = 0, i = 0; if (!get_smart_values(drive, page)) { unsigned short *val = (unsigned short *) page; @@ -542,11 +590,61 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static int proc_idedisk_read_tcq + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct ata_device *drive = (struct ata_device *) data; + char *out = page; + int len, cmds, i; + unsigned long flags; + + if (!blk_queue_tagged(&drive->queue)) { + len = sprintf(out, "not configured\n"); + PROC_IDE_READ_RETURN(page, start, off, count, eof, len); + } + + spin_lock_irqsave(&ide_lock, flags); + + len = sprintf(out, "TCQ currently on:\t%s\n", drive->using_tcq ? "yes" : "no"); + len += sprintf(out+len, "Max queue depth:\t%d\n",drive->queue_depth); + len += sprintf(out+len, "Max achieved depth:\t%d\n",drive->max_depth); + len += sprintf(out+len, "Max depth since last:\t%d\n",drive->max_last_depth); + len += sprintf(out+len, "Current depth:\t\t%d\n", ata_pending_commands(drive)); + len += sprintf(out+len, "Active tags:\t\t[ "); + for (i = 0, cmds = 0; i < drive->queue_depth; i++) { + struct request *rq = blk_queue_tag_request(&drive->queue, i); + + if (!rq) + continue; + + len += sprintf(out+len, "%d, ", i); + cmds++; + } + len += sprintf(out+len, "]\n"); + + len += sprintf(out+len, "Queue:\t\t\treleased [ %lu ] - started [ %lu ]\n", drive->immed_rel, drive->immed_comp); + + if (ata_pending_commands(drive) != cmds) + len += sprintf(out+len, "pending request and queue count mismatch (counted: %d)\n", cmds); + + len += sprintf(out+len, "DMA status:\t\t%srunning\n", test_bit(IDE_DMA, &HWGROUP(drive)->flags) ? "" : "not "); + + drive->max_last_depth = 0; + + spin_unlock_irqrestore(&ide_lock, flags); + PROC_IDE_READ_RETURN(page, start, off, count, eof, len); +} +#endif + static ide_proc_entry_t idedisk_proc[] = { { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL }, { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL }, { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL }, { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL }, +#ifdef CONFIG_BLK_DEV_IDE_TCQ + { "tcq", S_IFREG|S_IRUSR, proc_idedisk_read_tcq, NULL }, +#endif { NULL, 0, NULL, NULL } }; @@ -560,7 +658,7 @@ * This is tightly woven into the driver->special can not touch. * DON'T do it again until a total personality rewrite is committed. */ -static int set_multcount(ide_drive_t *drive, int arg) +static int set_multcount(struct ata_device *drive, int arg) { struct request rq; @@ -572,12 +670,12 @@ drive->mult_req = arg; drive->special_cmd |= ATA_SPECIAL_MMODE; - ide_do_drive_cmd (drive, &rq, ide_wait); + ide_do_drive_cmd(drive, &rq, ide_wait); return (drive->mult_count == arg) ? 0 : -EIO; } -static int set_nowerr(ide_drive_t *drive, int arg) +static int set_nowerr(struct ata_device *drive, int arg) { if (ide_spin_wait_hwgroup(drive)) return -EBUSY; @@ -588,7 +686,7 @@ return 0; } -static int write_cache(ide_drive_t *drive, int arg) +static int write_cache(struct ata_device *drive, int arg) { struct ata_taskfile args; @@ -606,7 +704,7 @@ return 0; } -static int idedisk_standby(ide_drive_t *drive) +static int idedisk_standby(struct ata_device *drive) { struct ata_taskfile args; @@ -617,7 +715,7 @@ return ide_raw_taskfile(drive, &args, NULL); } -static int set_acoustic(ide_drive_t *drive, int arg) +static int set_acoustic(struct ata_device *drive, int arg) { struct ata_taskfile args; @@ -633,7 +731,33 @@ return 0; } -static int probe_lba_addressing (ide_drive_t *drive, int arg) +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static int set_using_tcq(struct ata_device *drive, int arg) +{ + if (!drive->driver) + return -EPERM; + if (!drive->channel->XXX_udma) + return -EPERM; + if (arg == drive->queue_depth && drive->using_tcq) + return 0; + + /* + * set depth, but check also id for max supported depth + */ + drive->queue_depth = arg ? arg : 1; + if (drive->id) { + if (drive->queue_depth > drive->id->queue_depth + 1) + drive->queue_depth = drive->id->queue_depth + 1; + } + + if (udma_tcq_enable(drive, arg)) + return -EIO; + + return 0; +} +#endif + +static int probe_lba_addressing(struct ata_device *drive, int arg) { drive->addressing = 0; @@ -644,12 +768,12 @@ return 0; } -static int set_lba_addressing (ide_drive_t *drive, int arg) +static int set_lba_addressing(struct ata_device *drive, int arg) { return (probe_lba_addressing(drive, arg)); } -static void idedisk_add_settings(ide_drive_t *drive) +static void idedisk_add_settings(struct ata_device *drive) { struct hd_driveid *id = drive->id; @@ -664,11 +788,14 @@ ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + ide_add_setting(drive, "using_tcq", SETTING_RW, HDIO_GET_QDMA, HDIO_SET_QDMA, TYPE_BYTE, 0, IDE_MAX_TAG, 1, 1, &drive->using_tcq, set_using_tcq); +#endif } static int idedisk_suspend(struct device *dev, u32 state, u32 level) { - ide_drive_t *drive = dev->driver_data; + struct ata_device *drive = dev->driver_data; /* I hope that every freeze operations from the upper levels have * already been done... @@ -695,7 +822,7 @@ static int idedisk_resume(struct device *dev, u32 level) { - ide_drive_t *drive = dev->driver_data; + struct ata_device *drive = dev->driver_data; if (level != RESUME_RESTORE_STATE) return 0; @@ -789,7 +916,7 @@ * Sets maximum virtual LBA address of the drive. * Returns new maximum virtual LBA address (> 0) or 0 on failure. */ -static sector_t set_max_address(ide_drive_t *drive, sector_t addr_req) +static sector_t set_max_address(struct ata_device *drive, sector_t addr_req) { struct ata_taskfile args; sector_t addr_set = 0; @@ -818,7 +945,7 @@ return addr_set; } -static u64 set_max_address_ext(ide_drive_t *drive, u64 addr_req) +static u64 set_max_address_ext(struct ata_device *drive, u64 addr_req) { struct ata_taskfile args; u64 addr_set = 0; @@ -1050,7 +1177,7 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) - (void) drive->channel->udma(ide_dma_verbose, drive, NULL); + udma_print(drive); #endif printk("\n"); @@ -1086,7 +1213,7 @@ probe_lba_addressing(drive, 1); } -static int idedisk_cleanup(ide_drive_t *drive) +static int idedisk_cleanup(struct ata_device *drive) { if (!drive) return 0; @@ -1123,7 +1250,7 @@ static void __exit idedisk_exit (void) { - ide_drive_t *drive; + struct ata_device *drive; int failed = 0; while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", &idedisk_driver, failed)) != NULL) { @@ -1140,9 +1267,9 @@ } } -int idedisk_init (void) +int idedisk_init(void) { - ide_drive_t *drive; + struct ata_device *drive; int failed = 0; MOD_INC_USE_COUNT; diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c --- a/drivers/ide/ide-dma.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-dma.c Sun May 5 20:39:49 2002 @@ -1,4 +1,5 @@ -/* +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * * Copyright (c) 1999-2000 Andre Hedrick * Copyright (c) 1995-1998 Mark Lord * @@ -63,12 +64,12 @@ * * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports. * - * check_drive_lists(ide_drive_t *drive, int good_bad) - * * ATA-66/100 and recovery functions, I forgot the rest...... */ #include +#define __NO_VERSION__ +#include #include #include #include @@ -192,19 +193,19 @@ #endif /* - * dma_intr() is the handler for disk read/write DMA interrupts + * This is the handler for disk read/write DMA interrupts. */ ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq) { - byte stat, dma_stat; + u8 stat, dma_stat; - dma_stat = drive->channel->udma(ide_dma_end, drive, rq); + dma_stat = udma_stop(drive); if (OK_STAT(stat = GET_STAT(),DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { if (!dma_stat) { __ide_end_request(drive, rq, 1, rq->nr_sectors); return ide_stopped; } - printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", + printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); } return ide_error(drive, "dma_intr", stat); @@ -270,106 +271,11 @@ } /* - * This prepares a dma request. Returns 0 if all went okay, returns 1 - * otherwise. May also be invoked from trm290.c - */ -int ide_build_dmatable(struct ata_device *drive, ide_dma_action_t func) -{ - struct ata_channel *ch = drive->channel; - unsigned int *table = ch->dmatable_cpu; -#ifdef CONFIG_BLK_DEV_TRM290 - unsigned int is_trm290_chipset = (ch->chipset == ide_trm290); -#else - const int is_trm290_chipset = 0; -#endif - unsigned int count = 0; - int i; - struct scatterlist *sg; - - ch->sg_nents = i = build_sglist(ch, HWGROUP(drive)->rq); - if (!i) - return 0; - - sg = ch->sg_table; - while (i) { - u32 cur_addr; - u32 cur_len; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - /* - * Fill in the dma table, without crossing any 64kB boundaries. - * Most hardware requires 16-bit alignment of all blocks, - * but the trm290 requires 32-bit alignment. - */ - - while (cur_len) { - u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); - - if (count++ >= PRD_ENTRIES) { - printk("ide-dma: count %d, sg_nents %d, cur_len %d, cur_addr %u\n", - count, ch->sg_nents, cur_len, cur_addr); - BUG(); - } - - if (bcount > cur_len) - bcount = cur_len; - *table++ = cpu_to_le32(cur_addr); - xcount = bcount & 0xffff; - if (is_trm290_chipset) - xcount = ((xcount >> 2) - 1) << 16; - if (xcount == 0x0000) { - /* - * Most chipsets correctly interpret a length of - * 0x0000 as 64KB, but at least one (e.g. CS5530) - * misinterprets it as zero (!). So here we break - * the 64KB entry into two 32KB entries instead. - */ - if (count++ >= PRD_ENTRIES) { - pci_unmap_sg(ch->pci_dev, sg, - ch->sg_nents, - ch->sg_dma_direction); - return 0; - } - - *table++ = cpu_to_le32(0x8000); - *table++ = cpu_to_le32(cur_addr + 0x8000); - xcount = 0x8000; - } - *table++ = cpu_to_le32(xcount); - cur_addr += bcount; - cur_len -= bcount; - } - - sg++; - i--; - } - - if (!count) - printk("%s: empty DMA table?\n", drive->name); - else if (!is_trm290_chipset) - *--table |= cpu_to_le32(0x80000000); - - return count; -} - -/* Teardown mappings after DMA has completed. */ -void ide_destroy_dmatable (ide_drive_t *drive) -{ - struct pci_dev *dev = drive->channel->pci_dev; - struct scatterlist *sg = drive->channel->sg_table; - int nents = drive->channel->sg_nents; - - pci_unmap_sg(dev, sg, nents, drive->channel->sg_dma_direction); -} - -/* * For both Blacklisted and Whitelisted drives. * This is setup to be called as an extern for future support * to other special driver code. */ -int check_drive_lists (ide_drive_t *drive, int good_bad) +int check_drive_lists(struct ata_device *drive, int good_bad) { struct hd_driveid *id = drive->id; @@ -382,7 +288,7 @@ printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return(blacklist); } -#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ +#else const char **list; if (good_bad) { @@ -403,84 +309,67 @@ } } } -#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ +#endif return 0; } -int report_drive_dmaing (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - - if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && - (id->dma_ultra & (id->dma_ultra >> 14) & 3)) { - if ((id->dma_ultra >> 15) & 1) { - printk(", UDMA(mode 7)"); /* UDMA BIOS-enabled! */ - } else { - printk(", UDMA(133)"); /* UDMA BIOS-enabled! */ - } - } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && - (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { - if ((id->dma_ultra >> 13) & 1) { - printk(", UDMA(100)"); /* UDMA BIOS-enabled! */ - } else if ((id->dma_ultra >> 12) & 1) { - printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ - } else { - printk(", UDMA(44)"); /* UDMA BIOS-enabled! */ - } - } else if ((id->field_valid & 4) && - (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { - if ((id->dma_ultra >> 10) & 1) { - printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ - } else if ((id->dma_ultra >> 9) & 1) { - printk(", UDMA(25)"); /* UDMA BIOS-enabled! */ - } else { - printk(", UDMA(16)"); /* UDMA BIOS-enabled! */ - } - } else if (id->field_valid & 4) { - printk(", (U)DMA"); /* Can be BIOS-enabled! */ - } else { - printk(", DMA"); - } - return 1; -} - -static int config_drive_for_dma (ide_drive_t *drive) +static int config_drive_for_dma(struct ata_device *drive) { int config_allows_dma = 1; struct hd_driveid *id = drive->id; - struct ata_channel *hwif = drive->channel; + struct ata_channel *ch = drive->channel; #ifdef CONFIG_IDEDMA_ONLYDISK if (drive->type != ATA_DISK) config_allows_dma = 0; #endif - if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) { + if (id && (id->capability & 1) && ch->autodma && config_allows_dma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) - return hwif->udma(ide_dma_off, drive, NULL); + if (udma_black_list(drive)) { + udma_enable(drive, 0, 1); + + return 0; + } /* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */ if ((id->field_valid & 4) && (eighty_ninty_three(drive))) - if ((id->dma_ultra & (id->dma_ultra >> 14) & 2)) - return hwif->udma(ide_dma_on, drive, NULL); + if ((id->dma_ultra & (id->dma_ultra >> 14) & 2)) { + udma_enable(drive, 1, 1); + + return 0; + } /* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */ if ((id->field_valid & 4) && (eighty_ninty_three(drive))) - if ((id->dma_ultra & (id->dma_ultra >> 11) & 7)) - return hwif->udma(ide_dma_on, drive, NULL); + if ((id->dma_ultra & (id->dma_ultra >> 11) & 7)) { + udma_enable(drive, 1, 1); + + return 0; + } /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ - if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) - return hwif->udma(ide_dma_on, drive, NULL); + if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) { + udma_enable(drive, 1, 1); + + return 0; + } /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */ if (id->field_valid & 2) /* regular DMA */ - if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) - return hwif->udma(ide_dma_on, drive, NULL); + if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) { + udma_enable(drive, 1, 1); + + return 0; + } /* Consult the list of known "good" drives */ - if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) - return hwif->udma(ide_dma_on, drive, NULL); + if (udma_white_list(drive)) { + udma_enable(drive, 1, 1); + + return 0; + } } - return hwif->udma(ide_dma_off_quietly, drive, NULL); + udma_enable(drive, 0, 0); + + return 0; } /* @@ -508,18 +397,24 @@ return 0; } -static void ide_toggle_bounce(ide_drive_t *drive, int on) +int ata_start_dma(struct ata_device *drive, struct request *rq) { - u64 addr = BLK_BOUNCE_HIGH; + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + unsigned int reading = 0; - if (on && drive->type == ATA_DISK && drive->channel->highmem) { - if (!PCI_DMA_BUS_IS_PHYS) - addr = BLK_BOUNCE_ANY; - else - addr = drive->channel->pci_dev->dma_mask; - } + if (rq_data_dir(rq) == READ) + reading = 1 << 3; - blk_queue_bounce_limit(&drive->queue, addr); + /* try PIO instead of DMA */ + if (!udma_new_table(ch, rq)) + return 1; + + outl(ch->dmatable_dma, dma_base + 4); /* PRD table */ + outb(reading, dma_base); /* specify r/w */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; + return 0; } /* @@ -531,162 +426,76 @@ * * For ATAPI devices, we just prepare for DMA and return. The caller should * then issue the packet command to the drive and call us again with - * ide_dma_begin afterwards. + * udma_start afterwards. * * Returns 0 if all went well. * Returns 1 if DMA read/write could not be started, in which case * the caller should revert to PIO for the current request. * May also be invoked from trm290.c */ -int ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +int XXX_ide_dmaproc(struct ata_device *drive) { - struct ata_channel *hwif = drive->channel; - unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); - unsigned int count, reading = 0, set_high = 1; - byte dma_stat; - - switch (func) { - case ide_dma_off: - printk("%s: DMA disabled\n", drive->name); - case ide_dma_off_quietly: - set_high = 0; - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - case ide_dma_on: - ide_toggle_bounce(drive, set_high); - drive->using_dma = (func == ide_dma_on); - if (drive->using_dma) - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - return 0; - case ide_dma_check: - return config_drive_for_dma (drive); - case ide_dma_read: - reading = 1 << 3; - case ide_dma_write: - /* active tuning based on IO direction */ - if (hwif->rwproc) - hwif->rwproc(drive, func); - - if (!(count = ide_build_dmatable(drive, func))) - return 1; /* try PIO instead of DMA */ - outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ - drive->waiting_for_dma = 1; - if (drive->type != ATA_DISK) - return 0; - - ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ - if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) { - struct ata_taskfile *args = rq->special; - - OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG); - } else if (drive->addressing) { - OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); - } else { - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - } - return drive->channel->udma(ide_dma_begin, drive, NULL); - case ide_dma_begin: - /* Note that this is done *after* the cmd has - * been issued to the drive, as per the BM-IDE spec. - * The Promise Ultra33 doesn't work correctly when - * we do this part before issuing the drive cmd. - */ - outb(inb(dma_base)|1, dma_base); /* start DMA */ - return 0; - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); -#if 0 /* do not set unless you know what you are doing */ - if (dma_stat & 4) { - byte stat = GET_STAT(); - outb(dma_base+2, dma_stat & 0xE4); - } -#endif - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ - case ide_dma_bad_drive: - case ide_dma_good_drive: - return check_drive_lists(drive, (func == ide_dma_good_drive)); - case ide_dma_verbose: - return report_drive_dmaing(drive); - case ide_dma_timeout: - printk(KERN_ERR "%s: DMA timeout occured!\n", __FUNCTION__); - return 1; - case ide_dma_retune: - case ide_dma_lostirq: - printk(KERN_ERR "%s: chipset supported func only: %d\n", __FUNCTION__, func); - return 1; - default: - printk(KERN_ERR "%s: unsupported func: %d\n", __FUNCTION__, func); - return 1; - } + return config_drive_for_dma(drive); } /* * Needed for allowing full modular support of ide-driver */ -void ide_release_dma(struct ata_channel *hwif) +void ide_release_dma(struct ata_channel *ch) { - if (!hwif->dma_base) + if (!ch->dma_base) return; - if (hwif->dmatable_cpu) { - pci_free_consistent(hwif->pci_dev, + if (ch->dmatable_cpu) { + pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES, - hwif->dmatable_cpu, - hwif->dmatable_dma); - hwif->dmatable_cpu = NULL; - } - if (hwif->sg_table) { - kfree(hwif->sg_table); - hwif->sg_table = NULL; - } - if ((hwif->dma_extra) && (hwif->unit == 0)) - release_region((hwif->dma_base + 16), hwif->dma_extra); - release_region(hwif->dma_base, 8); - hwif->dma_base = 0; + ch->dmatable_cpu, + ch->dmatable_dma); + ch->dmatable_cpu = NULL; + } + if (ch->sg_table) { + kfree(ch->sg_table); + ch->sg_table = NULL; + } + if ((ch->dma_extra) && (ch->unit == 0)) + release_region((ch->dma_base + 16), ch->dma_extra); + release_region(ch->dma_base, 8); + ch->dma_base = 0; } /* * This can be called for a dynamically installed interface. Don't __init it */ -void ide_setup_dma(struct ata_channel *hwif, unsigned long dma_base, unsigned int num_ports) +void ide_setup_dma(struct ata_channel *ch, unsigned long dma_base, unsigned int num_ports) { - printk(" %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1); + printk(" %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + num_ports - 1); if (check_region(dma_base, num_ports)) { printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n"); return; } - request_region(dma_base, num_ports, hwif->name); - hwif->dma_base = dma_base; - hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, + request_region(dma_base, num_ports, ch->name); + ch->dma_base = dma_base; + ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES, - &hwif->dmatable_dma); - if (hwif->dmatable_cpu == NULL) + &ch->dmatable_dma); + if (ch->dmatable_cpu == NULL) goto dma_alloc_failure; - hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, + ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL); - if (hwif->sg_table == NULL) { - pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES, - hwif->dmatable_cpu, hwif->dmatable_dma); + if (ch->sg_table == NULL) { + pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES, + ch->dmatable_cpu, ch->dmatable_dma); goto dma_alloc_failure; } - hwif->udma = ide_dmaproc; + ch->XXX_udma = XXX_ide_dmaproc; - if (hwif->chipset != ide_trm290) { - byte dma_stat = inb(dma_base+2); + if (ch->chipset != ide_trm290) { + u8 dma_stat = inb(dma_base+2); printk(", BIOS settings: %s:%s, %s:%s", - hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", - hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); + ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", + ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); } printk("\n"); return; @@ -694,3 +503,351 @@ dma_alloc_failure: printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n"); } + +/**************************************************************************** + * UDMA function which should have architecture specific counterparts where + * neccessary. + * + * The intention is that at some point in time we will move this whole to + * architecture specific kernel sections. For now I would love the architecture + * maintainers to just #ifdef #endif this stuff directly here. I have for now + * tryed to update as much as I could in the architecture specific code. But + * of course I may have done mistakes, so please bear with me and update it + * here the proper way. + * + * Thank you a lot in advance! + * + * Sat May 4 20:29:46 CEST 2002 Marcin Dalecki. + */ + +/* + * This is the generic part of the DMA setup used by the host chipset drivers + * in the corresponding DMA setup method. + * + * FIXME: there are some places where this gets used driectly for "error + * recovery" in the ATAPI drivers. This was just plain wrong before, in esp. + * not portable, and just got uncovered now. + */ +void udma_enable(struct ata_device *drive, int on, int verbose) +{ + struct ata_channel *ch = drive->channel; + int set_high = 1; + u8 unit = (drive->select.b.unit & 0x01); + u64 addr = BLK_BOUNCE_HIGH; + + if (!on) { + if (verbose) + printk("%s: DMA disabled\n", drive->name); + set_high = 0; + outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + udma_tcq_enable(drive, 0); +#endif + } + + /* toggle bounce buffers */ + + if (on && drive->type == ATA_DISK && drive->channel->highmem) { + if (!PCI_DMA_BUS_IS_PHYS) + addr = BLK_BOUNCE_ANY; + else + addr = drive->channel->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(&drive->queue, addr); + + drive->using_dma = on; + + if (on) { + outb(inb(ch->dma_base + 2) | (1 << (5 + unit)), ch->dma_base + 2); +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + udma_tcq_enable(drive, 1); +#endif + } +} + +/* + * This prepares a dma request. Returns 0 if all went okay, returns 1 + * otherwise. May also be invoked from trm290.c + */ +int udma_new_table(struct ata_channel *ch, struct request *rq) +{ + unsigned int *table = ch->dmatable_cpu; +#ifdef CONFIG_BLK_DEV_TRM290 + unsigned int is_trm290_chipset = (ch->chipset == ide_trm290); +#else + const int is_trm290_chipset = 0; +#endif + unsigned int count = 0; + int i; + struct scatterlist *sg; + + ch->sg_nents = i = build_sglist(ch, rq); + if (!i) + return 0; + + sg = ch->sg_table; + while (i) { + u32 cur_addr; + u32 cur_len; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + /* + * Fill in the dma table, without crossing any 64kB boundaries. + * Most hardware requires 16-bit alignment of all blocks, + * but the trm290 requires 32-bit alignment. + */ + + while (cur_len) { + u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); + + if (count++ >= PRD_ENTRIES) { + printk("ide-dma: count %d, sg_nents %d, cur_len %d, cur_addr %u\n", + count, ch->sg_nents, cur_len, cur_addr); + BUG(); + } + + if (bcount > cur_len) + bcount = cur_len; + *table++ = cpu_to_le32(cur_addr); + xcount = bcount & 0xffff; + if (is_trm290_chipset) + xcount = ((xcount >> 2) - 1) << 16; + if (xcount == 0x0000) { + /* + * Most chipsets correctly interpret a length of + * 0x0000 as 64KB, but at least one (e.g. CS5530) + * misinterprets it as zero (!). So here we break + * the 64KB entry into two 32KB entries instead. + */ + if (count++ >= PRD_ENTRIES) { + pci_unmap_sg(ch->pci_dev, sg, + ch->sg_nents, + ch->sg_dma_direction); + return 0; + } + + *table++ = cpu_to_le32(0x8000); + *table++ = cpu_to_le32(cur_addr + 0x8000); + xcount = 0x8000; + } + *table++ = cpu_to_le32(xcount); + cur_addr += bcount; + cur_len -= bcount; + } + + sg++; + i--; + } + + if (!count) + printk(KERN_ERR "%s: empty DMA table?\n", ch->name); + else if (!is_trm290_chipset) + *--table |= cpu_to_le32(0x80000000); + + return count; +} + +/* Teardown mappings after DMA has completed. */ +void udma_destroy_table(struct ata_channel *ch) +{ + pci_unmap_sg(ch->pci_dev, ch->sg_table, ch->sg_nents, ch->sg_dma_direction); +} + +void udma_print(struct ata_device *drive) +{ +#ifdef CONFIG_ARCH_ACORN + printk(", DMA"); +#else + struct hd_driveid *id = drive->id; + char *str = NULL; + + if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 14) & 3)) { + if ((id->dma_ultra >> 15) & 1) + str = ", UDMA(mode 7)"; /* UDMA BIOS-enabled! */ + else + str = ", UDMA(133)"; /* UDMA BIOS-enabled! */ + } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { + if ((id->dma_ultra >> 13) & 1) { + str = ", UDMA(100)"; /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 12) & 1) { + str = ", UDMA(66)"; /* UDMA BIOS-enabled! */ + } else { + str = ", UDMA(44)"; /* UDMA BIOS-enabled! */ + } + } else if ((id->field_valid & 4) && + (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { + if ((id->dma_ultra >> 10) & 1) { + str = ", UDMA(33)"; /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 9) & 1) { + str = ", UDMA(25)"; /* UDMA BIOS-enabled! */ + } else { + str = ", UDMA(16)"; /* UDMA BIOS-enabled! */ + } + } else if (id->field_valid & 4) + str = ", (U)DMA"; /* Can be BIOS-enabled! */ + else + str = ", DMA"; + + printk(str); +#endif +} + +/* + * Drive back/white list handling for UDMA capability: + */ + +int udma_black_list(struct ata_device *drive) +{ + return check_drive_lists(drive, 0); +} + +int udma_white_list(struct ata_device *drive) +{ + return check_drive_lists(drive, 1); +} + +/* + * Generic entry points for functions provided possibly by the host chip set + * drivers. + */ + +/* + * Prepare the channel for a DMA startfer. Please note that only the broken + * Pacific Digital host chip needs the reques to be passed there to decide + * about addressing modes. + */ + +int udma_start(struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + + if (ch->udma_start) + return ch->udma_start(drive, rq); + + /* Note that this is done *after* the cmd has + * been issued to the drive, as per the BM-IDE spec. + * The Promise Ultra33 doesn't work correctly when + * we do this part before issuing the drive cmd. + */ + outb(inb(dma_base)|1, dma_base); /* start DMA */ + return 0; +} + +int udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + if (ch->udma_stop) + return ch->udma_stop(drive); + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* purge DMA mappings */ + + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ +} + +/* + * This is the default read write function. + * + * It's exported only for host chips which use it for fallback or (too) late + * capability checking. + */ + +int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq) +{ + if (ata_start_dma(drive, rq)) + return 1; + + if (drive->type != ATA_DISK) + return 0; + + reading <<= 3; + + ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ + if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) { + struct ata_taskfile *args = rq->special; + + OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG); + } else if (drive->addressing) { + OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + } + + return udma_start(drive, rq); +} + +int udma_read(struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + + if (ch->udma_read) + return ch->udma_read(drive, rq); + + return ata_do_udma(1, drive, rq); +} + +int udma_write(struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + + if (ch->udma_write) + return ch->udma_write(drive, rq); + + return ata_do_udma(0, drive, rq); +} + +/* + * FIXME: This should be attached to a channel as we can see now! + */ +int udma_irq_status(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + u8 dma_stat; + + if (ch->udma_irq_status) + return ch->udma_irq_status(drive); + + /* default action */ + dma_stat = inb(ch->dma_base + 2); + + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ +} + +void udma_timeout(struct ata_device *drive) +{ + printk(KERN_ERR "ATA: UDMA timeout occured %s!\n", drive->name); + + /* Invoke the chipset specific handler now. */ + if (drive->channel->udma_timeout) + drive->channel->udma_timeout(drive); + +} + +void udma_irq_lost(struct ata_device *drive) +{ + if (drive->channel->udma_irq_lost) + drive->channel->udma_irq_lost(drive); +} + +EXPORT_SYMBOL(udma_enable); +EXPORT_SYMBOL(udma_start); +EXPORT_SYMBOL(udma_stop); +EXPORT_SYMBOL(udma_read); +EXPORT_SYMBOL(udma_write); +EXPORT_SYMBOL(ata_do_udma); +EXPORT_SYMBOL(udma_irq_status); +EXPORT_SYMBOL(udma_print); +EXPORT_SYMBOL(udma_black_list); +EXPORT_SYMBOL(udma_white_list); diff -Nru a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c --- a/drivers/ide/ide-features.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/ide-features.c Sun May 5 20:39:50 2002 @@ -44,29 +44,38 @@ */ char *ide_xfer_verbose (byte xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_7: return("UDMA 7"); - case XFER_UDMA_6: return("UDMA 6"); - case XFER_UDMA_5: return("UDMA 5"); - case XFER_UDMA_4: return("UDMA 4"); - case XFER_UDMA_3: return("UDMA 3"); - case XFER_UDMA_2: return("UDMA 2"); - case XFER_UDMA_1: return("UDMA 1"); - case XFER_UDMA_0: return("UDMA 0"); - case XFER_MW_DMA_2: return("MW DMA 2"); - case XFER_MW_DMA_1: return("MW DMA 1"); - case XFER_MW_DMA_0: return("MW DMA 0"); - case XFER_SW_DMA_2: return("SW DMA 2"); - case XFER_SW_DMA_1: return("SW DMA 1"); - case XFER_SW_DMA_0: return("SW DMA 0"); - case XFER_PIO_4: return("PIO 4"); - case XFER_PIO_3: return("PIO 3"); - case XFER_PIO_2: return("PIO 2"); - case XFER_PIO_1: return("PIO 1"); - case XFER_PIO_0: return("PIO 0"); - case XFER_PIO_SLOW: return("PIO SLOW"); - default: return("XFER ERROR"); - } + static struct ide_xfer_par { + byte rate; + char *name; + } xfer_verbose[] = { + { XFER_UDMA_7, "UDMA 7" }, + { XFER_UDMA_6, "UDMA 6" }, + { XFER_UDMA_5, "UDMA 5" }, + { XFER_UDMA_4, "UDMA 4" }, + { XFER_UDMA_3, "UDMA 3" }, + { XFER_UDMA_2, "UDMA 2" }, + { XFER_UDMA_1, "UDMA 1" }, + { XFER_UDMA_0, "UDMA 0" }, + { XFER_MW_DMA_2, "MW DMA 2" }, + { XFER_MW_DMA_1, "MW DMA 1" }, + { XFER_MW_DMA_0, "MW DMA 0" }, + { XFER_SW_DMA_2, "SW DMA 2" }, + { XFER_SW_DMA_1, "SW DMA 1" }, + { XFER_SW_DMA_0, "SW DMA 0" }, + { XFER_PIO_4, "PIO 4" }, + { XFER_PIO_3, "PIO 3" }, + { XFER_PIO_2, "PIO 2" }, + { XFER_PIO_1, "PIO 1" }, + { XFER_PIO_0, "PIO 0" }, + { XFER_PIO_SLOW, "PIO SLOW" }, + }; + + int i = 0; + + for (; i < ARRAY_SIZE(xfer_verbose); i++) + if (xfer_verbose[i].rate == xfer_rate) + return xfer_verbose[i].name; + return "XFER ERROR"; } byte ide_auto_reduce_xfer (ide_drive_t *drive) diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-floppy.c Sun May 5 20:39:49 2002 @@ -901,7 +901,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - if (drive->channel->udma(ide_dma_end, drive, NULL)) { + if (udma_stop(drive)) { set_bit (PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred=pc->request_transfer; @@ -944,10 +944,11 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n"); - drive->channel->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); + return ide_stopped; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG); /* on this interrupt */ ireason.all=IN_BYTE (IDE_IREASON_REG); @@ -1119,11 +1120,15 @@ bcount.all = min(pc->request_transfer, 63 * 1024); #ifdef CONFIG_BLK_DEV_IDEDMA - if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { - (void) drive->channel->udma(ide_dma_off, drive, NULL); + if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) + udma_enable(drive, 0, 1); + + if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) { + if (test_bit (PC_WRITING, &pc->flags)) + dma_ok = !udma_write(drive, rq); + else + dma_ok = !udma_read(drive, rq); } - if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok=!drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq); #endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) @@ -1136,7 +1141,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); - (void) drive->channel->udma(ide_dma_begin, drive, NULL); + udma_start(drive, rq); } #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c --- a/drivers/ide/ide-pci.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/ide-pci.c Sun May 5 20:39:50 2002 @@ -1,6 +1,8 @@ -/* - * Copyright (c) 1998-2000 Andre Hedrick - * Copyright (c) 1995-1998 Mark Lord +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 2002 Marcin Dalecki + * Copyright (C) 1998-2000 Andre Hedrick + * Copyright (C) 1995-1998 Mark Lord * * May be copied or modified under the terms of the GNU General Public License */ @@ -81,17 +83,10 @@ #endif #ifdef CONFIG_BLK_DEV_HPT366 -extern byte hpt363_shared_irq; -extern byte hpt363_shared_pin; - extern unsigned int pci_init_hpt366(struct pci_dev *); extern unsigned int ata66_hpt366(struct ata_channel *); extern void ide_init_hpt366(struct ata_channel *); extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long); -#else -/* FIXME: those have to be killed */ -static byte hpt363_shared_irq; -static byte hpt363_shared_pin; #endif #ifdef CONFIG_BLK_DEV_NS87415 @@ -177,7 +172,7 @@ #define ATA_F_PHACK 0x40 /* apply PROMISE hacks */ #define ATA_F_HPTHACK 0x80 /* apply HPT366 hacks */ -typedef struct ide_pci_device_s { +struct ata_pci_device { unsigned short vendor; unsigned short device; unsigned int (*init_chipset)(struct pci_dev *dev); @@ -188,9 +183,9 @@ unsigned int bootable; unsigned int extra; unsigned int flags; -} ide_pci_device_t; +}; -static ide_pci_device_t pci_chipsets[] __initdata = { +static struct ata_pci_device pci_chipsets[] __initdata = { #ifdef CONFIG_BLK_DEV_PIIX {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, @@ -319,7 +314,7 @@ * settings of split-mirror pci-config space, place chipset into init-mode, * and/or preserve an interrupt if the card is not native ide support. */ -static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *dev) +static unsigned int __init trust_pci_irq(struct ata_pci_device *d, struct pci_dev *dev) { if (d->flags & ATA_F_IRQ) return dev->irq; @@ -484,7 +479,7 @@ * Setup DMA transfers on a channel. */ static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev, - ide_pci_device_t *d, + struct ata_pci_device *d, int port, u8 class_rev, int pciirq, @@ -534,7 +529,7 @@ * This gets called once for the master and for the slave interface. */ static int __init setup_host_channel(struct pci_dev *dev, - ide_pci_device_t *d, + struct ata_pci_device *d, int port, u8 class_rev, int pciirq, @@ -648,17 +643,16 @@ } /* - * Looks at the primary/secondary channels on a PCI IDE device and, if they - * are enabled, prepares the IDE driver for use with them. This generic code - * works for most PCI chipsets. + * Looks at the primary/secondary channels on a PCI IDE device and, if they are + * enabled, prepares the IDE driver for use with them. This generic code works + * for most PCI chipsets. * * One thing that is not standardized is the location of the primary/secondary * interface "enable/disable" bits. For chipsets that we "know" about, this - * information is in the ide_pci_device_t struct; for all other chipsets, we - * just assume both interfaces are enabled. + * information is in the struct ata_pci_device struct; for all other chipsets, + * we just assume both interfaces are enabled. */ - -static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) +static void __init setup_pci_device(struct pci_dev *dev, struct ata_pci_device *d) { int autodma = 0; int pciirq = 0; @@ -715,7 +709,7 @@ d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; } - printk("%s: chipset revision %d\n", dev->name, class_rev); + printk(KERN_INFO "ATA: chipset rev.: %d\n", class_rev); /* * Can we trust the reported IRQ? @@ -728,11 +722,11 @@ to act otherwise on those. The Supertrak however we need to skip */ if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20265) { - printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n"); + printk(KERN_INFO "ATA: Found promise 20265 in RAID mode.\n"); if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) { - printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n"); + printk(KERN_INFO "ATA: Skipping Promise PDC20265 attached to I2O RAID controller.\n"); return; } } @@ -740,9 +734,10 @@ Suspect a fastrak and fall through */ } if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { - printk("%s: not 100%% native mode: will probe irqs later\n", dev->name); + printk(KERN_INFO "ATA: non-legacy mode: IRQ probe delayed\n"); + /* - * This allows off board ide-pci cards the enable a BIOS, + * This allows off board ide-pci cards to enable a BIOS, * verify interrupt settings of split-mirror pci-config * space, place chipset into init-mode, and/or preserve * an interrupt if the card is not native ide support. @@ -752,19 +747,18 @@ else pciirq = trust_pci_irq(d, dev); } else if (tried_config) { - printk("%s: will probe IRQs later\n", dev->name); + printk(KERN_INFO "ATA: will probe IRQs later\n"); pciirq = 0; } else if (!pciirq) { - printk("%s: bad IRQ (%d): will probe later\n", dev->name, pciirq); + printk(KERN_INFO "ATA: invalid IRQ (%d): will probe later\n", pciirq); pciirq = 0; } else { if (d->init_chipset) d->init_chipset(dev); #ifdef __sparc__ - printk("%s: 100%% native mode on irq %s\n", - dev->name, __irq_itoa(pciirq)); + printk(KERN_INFO "ATA: 100%% native mode on irq\n", __irq_itoa(pciirq)); #else - printk("%s: 100%% native mode on irq %d\n", dev->name, pciirq); + printk(KERN_INFO "ATA: 100%% native mode on irq %d\n", pciirq); #endif } @@ -775,10 +769,11 @@ setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma, &pcicmd); } -static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +static void __init pdc20270_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d) { - struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; + struct pci_dev *dev2 = NULL; + struct pci_dev *findev; + struct ata_pci_device *d2; if (dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_DEC && @@ -814,10 +809,10 @@ setup_pci_device(dev2, d2); } -static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +static void __init hpt366_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d) { struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; + struct ata_pci_device *d2; unsigned char pin1 = 0, pin2 = 0; unsigned int class_rev; @@ -843,9 +838,7 @@ (PCI_FUNC(findev->devfn) & 1)) { dev2 = findev; pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - hpt363_shared_pin = (pin1 != pin2) ? 1 : 0; - hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; - if (hpt363_shared_pin && hpt363_shared_irq) { + if ((pin1 != pin2) && (dev->irq == dev2->irq)) { d->bootable = ON_BOARD; printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2); } @@ -869,7 +862,7 @@ { unsigned short vendor; unsigned short device; - ide_pci_device_t *d; + struct ata_pci_device *d; vendor = dev->vendor; device = dev->device; @@ -881,7 +874,7 @@ ++d; if (d->init_channel == ATA_PCI_IGNORE) - printk("%s: has been ignored by PCI bus scan\n", dev->name); + printk(KERN_INFO "ATA: %s: ignored by PCI bus scan\n", dev->name); else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1)) return; else if ((d->vendor == PCI_VENDOR_ID_CONTAQ && d->device == PCI_DEVICE_ID_CONTAQ_82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) @@ -896,10 +889,10 @@ pdc20270_device_order_fixup(dev, d); else if (!(d->vendor == 0 && d->device == 0) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (d->vendor == 0 && d->device == 0) - printk("%s: unknown IDE controller on PCI slot %s, vendor=%04x, device=%04x\n", - dev->name, dev->slot_name, vendor, device); + printk(KERN_INFO "ATA: unknown interface: %s (%04x:%04x) on PCI slot %s\n", + dev->name, vendor, device, dev->slot_name); else - printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name); + printk(KERN_INFO "ATA: interface: %s, on PCI slot %s\n", dev->name, dev->slot_name); setup_pci_device(dev, d); } } diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c --- a/drivers/ide/ide-pmac.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/ide-pmac.c Sun May 5 20:39:50 2002 @@ -1164,9 +1164,9 @@ /* Teardown mappings after DMA has completed. */ static void -pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix) +pmac_ide_destroy_dmatable(struct ata_channel *ch, int ix) { - struct pci_dev *dev = drive->channel->pci_dev; + struct pci_dev *dev = ch->pci_dev; struct scatterlist *sg = pmac_ide[ix].sg_table; int nents = pmac_ide[ix].sg_nents; @@ -1367,10 +1367,6 @@ break; case ide_dma_read: case ide_dma_write: - /* this almost certainly isn't needed since we don't - appear to have a rwproc */ - if (drive->channel->rwproc) - drive->channel->rwproc(drive, func); reading = (func == ide_dma_read); if (!pmac_ide_build_dmatable(drive, rq, ix, !reading)) return 1; @@ -1404,7 +1400,7 @@ drive->waiting_for_dma = 0; dstat = in_le32(&dma->status); out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16)); - pmac_ide_destroy_dmatable(drive, ix); + pmac_ide_destroy_dmatable(drive->channel, ix); /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ @@ -1453,9 +1449,6 @@ case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); - case ide_dma_verbose: - return report_drive_dmaing(drive); - case ide_dma_retune: case ide_dma_lostirq: case ide_dma_timeout: printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported func only: %d\n", func); diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-probe.c Sun May 5 20:39:49 2002 @@ -1,4 +1,5 @@ -/* +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) * * Mostly written by Mark Lord @@ -47,7 +48,7 @@ #include #include -static inline void do_identify (ide_drive_t *drive, byte cmd) +static inline void do_identify(struct ata_device *drive, u8 cmd) { int bswap = 1; struct hd_driveid *id; @@ -121,7 +122,7 @@ drive->present = 1; /* - * Check for an ATAPI device + * Check for an ATAPI device: */ if (cmd == WIN_PIDENTIFY) { byte type = (id->config >> 8) & 0x1f; @@ -172,7 +173,7 @@ } /* - * Not an ATAPI device: looks like a "regular" hard disk + * Not an ATAPI device: looks like a "regular" hard disk: */ if (id->config & (1<<7)) drive->removable = 1; @@ -185,7 +186,7 @@ */ if (drive_is_flashcard(drive)) { - ide_drive_t *mate = &drive->channel->drives[1 ^ drive->select.b.unit]; + struct ata_device *mate = &drive->channel->drives[1 ^ drive->select.b.unit]; if (!mate->ata_flash) { mate->present = 0; mate->noprobe = 1; @@ -198,32 +199,53 @@ if (drive->channel->quirkproc) drive->quirk_list = drive->channel->quirkproc(drive); + /* Initialize queue depth settings */ + drive->queue_depth = 1; +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH + drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH; +#else + drive->queue_depth = drive->id->queue_depth + 1; +#endif + if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG) + drive->queue_depth = IDE_MAX_TAG; + return; err_misc: kfree(id); err_kmalloc: drive->present = 0; + return; } /* - * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive - * and waits for a response. It also monitors irqs while this is - * happening, in hope of automatically determining which one is - * being used by the interface. + * Sends an ATA(PI) IDENTIFY request to a drive and wait for a response. It + * also monitor irqs while this is happening, in hope of automatically + * determining which one is being used by the interface. * * Returns: 0 device was identified * 1 device timed-out (no response to identify request) * 2 device aborted the command (refused to identify itself) */ -static int actual_try_to_identify (ide_drive_t *drive, byte cmd) +static int identify(struct ata_device *drive, u8 cmd) { int rc; + int autoprobe = 0; + unsigned long cookie = 0; ide_ioreg_t hd_status; unsigned long timeout; - byte s, a; + u8 s; + u8 a; + + if (IDE_CONTROL_REG && !drive->channel->irq) { + autoprobe = 1; + cookie = probe_irq_on(); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ + } + + rc = 1; if (IDE_CONTROL_REG) { /* take a deep breath */ ide_delay_50ms(); @@ -247,19 +269,18 @@ #if CONFIG_BLK_DEV_PDC4030 if (drive->channel->chipset == ide_pdc4030) { /* DC4030 hosted drives need their own identify... */ - extern int pdc4030_identify(ide_drive_t *); - if (pdc4030_identify(drive)) { - return 1; - } + extern int pdc4030_identify(struct ata_device *); + + if (pdc4030_identify(drive)) + goto out; } else -#endif /* CONFIG_BLK_DEV_PDC4030 */ +#endif OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */ timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { - if (0 < (signed long)(jiffies - timeout)) { - return 1; /* drive timed-out */ - } + if (time_after(jiffies, timeout)) + goto out; /* drive timed-out */ ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(hd_status) & BUSY_STAT); @@ -274,23 +295,8 @@ __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ - return rc; -} - -static int try_to_identify (ide_drive_t *drive, byte cmd) -{ - int retval; - int autoprobe = 0; - unsigned long cookie = 0; - - if (IDE_CONTROL_REG && !drive->channel->irq) { - autoprobe = 1; - cookie = probe_irq_on(); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ - } - - retval = actual_try_to_identify(drive, cmd); +out: if (autoprobe) { int irq; OUT_BYTE(drive->ctl | 0x02, IDE_CONTROL_REG); /* mask device irq */ @@ -304,7 +310,8 @@ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); } } - return retval; + + return rc; } @@ -324,10 +331,11 @@ * 3 bad status from device (possible for ATAPI drives) * 4 probe was not attempted because failure was obvious */ -static int do_probe (ide_drive_t *drive, byte cmd) +static int do_probe(struct ata_device *drive, byte cmd) { int rc; struct ata_channel *hwif = drive->channel; + if (drive->present) { /* avoid waiting for inappropriate probes */ if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY)) return 4; @@ -348,11 +356,10 @@ return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } - if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) - || drive->present || cmd == WIN_PIDENTIFY) + if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY) { - if ((rc = try_to_identify(drive,cmd))) /* send cmd and wait */ - rc = try_to_identify(drive,cmd); /* failed: try again */ + if ((rc = identify(drive,cmd))) /* send cmd and wait */ + rc = identify(drive,cmd); /* failed: try again */ if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) { unsigned long timeout; printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT()); @@ -363,14 +370,14 @@ timeout = jiffies; while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE)) ide_delay_50ms(); - rc = try_to_identify(drive, cmd); + rc = identify(drive, cmd); } if (rc == 1) printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT()); (void) GET_STAT(); /* ensure drive irq is clear */ - } else { + } else rc = 3; /* not present or maybe ATAPI */ - } + if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ ide_delay_50ms(); @@ -379,10 +386,7 @@ return rc; } -/* - * - */ -static void enable_nest(ide_drive_t *drive) +static void enable_nest(struct ata_device *drive) { unsigned long timeout; @@ -392,7 +396,7 @@ OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; do { - if (jiffies > timeout) { + if (time_after(jiffies, timeout)) { printk("failed (timeout)\n"); return; } @@ -411,17 +415,21 @@ /* * Tests for existence of a given drive using do_probe(). */ -static inline void probe_for_drive (ide_drive_t *drive) +static inline void probe_for_drive(struct ata_device *drive) { if (drive->noprobe) /* skip probing? */ return; + if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ } + if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) enable_nest(drive); + if (!drive->present) return; /* drive not found */ + if (drive->id == NULL) { /* identification failed? */ if (drive->type == ATA_DISK) { printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", @@ -440,7 +448,7 @@ */ static void channel_probe(struct ata_channel *ch) { - unsigned int unit; + unsigned int i; unsigned long flags; int error; @@ -455,8 +463,8 @@ /* * Check for the presence of a channel by probing for drives on it. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &ch->drives[unit]; + for (i = 0; i < MAX_DRIVES; ++i) { + struct ata_device *drive = &ch->drives[i]; probe_for_drive(drive); @@ -475,23 +483,8 @@ error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name); ch->straight8 = 1; } else { - if (ch->io_ports[IDE_DATA_OFFSET]) - error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_ERROR_OFFSET]) - error += !request_region(ch->io_ports[IDE_ERROR_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_NSECTOR_OFFSET]) - error += !request_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_SECTOR_OFFSET]) - error += !request_region(ch->io_ports[IDE_SECTOR_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_LCYL_OFFSET]) - error += !request_region(ch->io_ports[IDE_LCYL_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_HCYL_OFFSET]) - error += !request_region(ch->io_ports[IDE_HCYL_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_SELECT_OFFSET]) - error += !request_region(ch->io_ports[IDE_SELECT_OFFSET], 1, ch->name); - if (ch->io_ports[IDE_STATUS_OFFSET]) - error += !request_region(ch->io_ports[IDE_STATUS_OFFSET], 1, ch->name); - + for (i = 0; i < 8; i++) + error += !request_region(ch->io_ports[i], 1, ch->name); } if (ch->io_ports[IDE_CONTROL_OFFSET]) error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name); @@ -545,7 +538,7 @@ do { ide_delay_50ms(); stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]); - } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); + } while ((stat & BUSY_STAT) && time_before(jiffies, timeout)); } __restore_flags(flags); /* local CPU only */ @@ -553,8 +546,8 @@ /* * Now setup the PIO transfer modes of the drives on this channel. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &ch->drives[unit]; + for (i = 0; i < MAX_DRIVES; ++i) { + struct ata_device *drive = &ch->drives[i]; if (drive->present && (drive->autotune == 1)) { if (drive->channel->tuneproc) @@ -569,60 +562,6 @@ } /* - * init request queue - */ -static void init_device_queue(struct ata_device *drive) -{ - request_queue_t *q = &drive->queue; - int max_sectors = 255; - - q->queuedata = drive->channel; - blk_init_queue(q, do_ide_request, &ide_lock); - blk_queue_segment_boundary(q, 0xffff); - - /* IDE can do up to 128K per request, pdc4030 needs smaller limit */ -#ifdef CONFIG_BLK_DEV_PDC4030 - if (drive->channel->chipset == ide_pdc4030) - max_sectors = 127; -#endif - blk_queue_max_sectors(q, max_sectors); - - /* IDE DMA can do PRD_ENTRIES number of segments. */ - blk_queue_max_hw_segments(q, PRD_SEGMENTS); - - /* This is a driver limit and could be eliminated. */ - blk_queue_max_phys_segments(q, PRD_SEGMENTS); -} - -#if MAX_HWIFS > 1 - -/* - * This is used to simplify logic in init_irq() below. - * - * A loophole here is that we may not know about a particular hwif's irq until - * after that hwif is actually probed/initialized.. This could be a problem - * for the case where an hwif is on a dual interface that requires - * serialization (eg. cmd640) and another hwif using one of the same irqs is - * initialized beforehand. - * - * This routine detects and reports such situations, but does not fix them. - */ -static void save_match(struct ata_channel *hwif, struct ata_channel *new, - struct ata_channel **match) -{ - struct ata_channel *m = *match; - - if (m && m->hwgroup && m->hwgroup != new->hwgroup) { - if (!new->hwgroup) - return; - printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name); - } - if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */ - *match = new; -} -#endif - -/* * This routine sets up the irq for an ide interface, and creates a new hwgroup * for the irq/channel if none was previously assigned. * @@ -643,10 +582,8 @@ ide_hwgroup_t *new_hwgroup; struct ata_channel *match = NULL; - - /* Allocate the buffer and potentially sleep first */ - - new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL); + /* Spare allocation before sleep. */ + new_hwgroup = kmalloc(sizeof(*hwgroup), GFP_KERNEL); spin_lock_irqsave(&ide_lock, flags); ch->hwgroup = NULL; @@ -658,19 +595,22 @@ for (i = 0; i < MAX_HWIFS; ++i) { struct ata_channel *h = &ide_hwifs[i]; - if (h->hwgroup) { /* scan only initialized channels */ - if (ch->irq == h->irq) { - ch->sharing_irq = h->sharing_irq = 1; - if (ch->chipset != ide_pci || h->chipset != ide_pci) - save_match(ch, h, &match); - - /* FIXME: This is still confusing. What would - * happen if we match-ed two times? - */ - - if (ch->serialized || h->serialized) - save_match(ch, h, &match); - } + /* scan only initialized channels */ + if (!h->hwgroup) + continue; + + if (ch->irq != h->irq) + continue; + + ch->sharing_irq = h->sharing_irq = 1; + + if (ch->chipset != ide_pci || h->chipset != ide_pci || + ch->serialized || h->serialized) { + if (match && match->hwgroup && match->hwgroup != h->hwgroup) + printk("%s: potential irq problem with %s and %s\n", ch->name, h->name, match->name); + /* don't undo a prior perfect match */ + if (!match || match->irq != ch->irq) + match = h; } } #endif @@ -721,6 +661,8 @@ ch->hwgroup = hwgroup; for (i = 0; i < MAX_DRIVES; ++i) { struct ata_device *drive = &ch->drives[i]; + request_queue_t *q; + int max_sectors = 255; if (!drive->present) continue; @@ -728,7 +670,27 @@ if (!hwgroup->XXX_drive) hwgroup->XXX_drive = drive; - init_device_queue(drive); + /* + * Init the per device request queue + */ + + q = &drive->queue; + q->queuedata = drive->channel; + blk_init_queue(q, do_ide_request, &ide_lock); + blk_queue_segment_boundary(q, 0xffff); + + /* ATA can do up to 128K per request, pdc4030 needs smaller limit */ +#ifdef CONFIG_BLK_DEV_PDC4030 + if (drive->channel->chipset == ide_pdc4030) + max_sectors = 127; +#endif + blk_queue_max_sectors(q, max_sectors); + + /* IDE DMA can do PRD_ENTRIES number of segments. */ + blk_queue_max_hw_segments(q, PRD_ENTRIES); + + /* FIXME: This is a driver limit and could be eliminated. */ + blk_queue_max_phys_segments(q, PRD_ENTRIES); } spin_unlock_irqrestore(&ide_lock, flags); @@ -755,80 +717,10 @@ } /* - * init_gendisk() (as opposed to ide_geninit) is called for each major device, - * after probing for drives, to allocate partition tables and other data - * structures needed for the routines in genhd.c. ide_geninit() gets called - * somewhat later, during the partition check. - */ -static void init_gendisk(struct ata_channel *hwif) -{ - struct gendisk *gd; - unsigned int unit, minors, i; - extern devfs_handle_t ide_devfs_handle; - - minors = MAX_DRIVES * (1 << PARTN_BITS); - - gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); - if (!gd) - goto err_kmalloc_gd; - - gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); - if (!gd->sizes) - goto err_kmalloc_gd_sizes; - - gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); - if (!gd->part) - goto err_kmalloc_gd_part; - memset(gd->part, 0, minors * sizeof(struct hd_struct)); - - for (unit = 0; unit < MAX_DRIVES; ++unit) - hwif->drives[unit].part = &gd->part[unit << PARTN_BITS]; - - gd->major = hwif->major; /* our major device number */ - gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ - gd->minor_shift = PARTN_BITS; /* num bits for partitions */ - gd->nr_real = MAX_DRIVES; /* current num real drives */ - gd->next = NULL; /* linked list of major devs */ - gd->fops = ide_fops; /* file operations */ - gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); - gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); - if (gd->de_arr) - memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); - if (gd->flags) - memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); - - hwif->gd = gd; - add_gendisk(gd); - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - char name[80]; - - ide_add_generic_settings(hwif->drives + unit); - hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit); - sprintf (name, "host%d/bus%d/target%d/lun%d", - hwif->index, hwif->unit, unit, hwif->drives[unit].lun); - if (hwif->drives[unit].present) - hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); - } - return; - -err_kmalloc_bs: - kfree(gd->part); -err_kmalloc_gd_part: - kfree(gd->sizes); -err_kmalloc_gd_sizes: - kfree(gd); -err_kmalloc_gd: - printk(KERN_CRIT "(ide::init_gendisk) Out of memory\n"); - return; -} - -/* * Returns the queue which corresponds to a given device. * * FIXME: this should take struct block_device * as argument in future. */ - static request_queue_t *ata_get_queue(kdev_t dev) { struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data; @@ -837,8 +729,15 @@ return &ch->drives[DEVICE_NR(dev) & 1].queue; } +/* Number of minor numbers we consume par channel. */ +#define ATA_MINORS (MAX_DRIVES * (1 << PARTN_BITS)) + static void channel_init(struct ata_channel *ch) { + struct gendisk *gd; + unsigned int unit; + extern devfs_handle_t ide_devfs_handle; + if (!ch->present) return; @@ -888,33 +787,106 @@ printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq); } - init_gendisk(ch); + /* Initialize partition and global device data. ide_geninit() gets + * called somewhat later, during the partition check. + */ + + gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); + if (!gd) + goto err_kmalloc_gd; + + gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL); + if (!gd->sizes) + goto err_kmalloc_gd_sizes; + + gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL); + if (!gd->part) + goto err_kmalloc_gd_part; + memset(gd->part, 0, ATA_MINORS * sizeof(struct hd_struct)); + + gd->de_arr = kmalloc (sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); + if (!gd->de_arr) + goto err_kmalloc_gd_de_arr; + memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); + + gd->flags = kmalloc (sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); + if (!gd->flags) + goto err_kmalloc_gd_flags; + memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); + + for (unit = 0; unit < MAX_DRIVES; ++unit) + ch->drives[unit].part = &gd->part[unit << PARTN_BITS]; + + gd->major = ch->major; /* our major device number */ + gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ + gd->minor_shift = PARTN_BITS; /* num bits for partitions */ + gd->nr_real = MAX_DRIVES; /* current num real drives */ + gd->next = NULL; /* linked list of major devs */ + gd->fops = ide_fops; /* file operations */ + + gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); + if (gd->de_arr) + memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); + else + goto err_kmalloc_gd_de_arr; + + gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); + if (gd->flags) + memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); + else + goto err_kmalloc_gd_flags; + + ch->gd = gd; + add_gendisk(gd); + + for (unit = 0; unit < MAX_DRIVES; ++unit) { + char name[80]; + + ide_add_generic_settings(ch->drives + unit); + ch->drives[unit].dn = ((ch->unit ? 2 : 0) + unit); + sprintf(name, "host%d/bus%d/target%d/lun%d", + ch->index, ch->unit, unit, ch->drives[unit].lun); + if (ch->drives[unit].present) + ch->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); + } + blk_dev[ch->major].data = ch; blk_dev[ch->major].queue = ata_get_queue; - /* all went well, flag this channel entry as valid */ + /* All went well, flag this channel entry as valid again. */ ch->present = 1; return; + +err_kmalloc_gd_flags: + kfree(gd->de_arr); +err_kmalloc_gd_de_arr: + kfree(gd->part); +err_kmalloc_gd_part: + kfree(gd->sizes); +err_kmalloc_gd_sizes: + kfree(gd); +err_kmalloc_gd: + printk(KERN_CRIT "(%s) Out of memory\n", __FUNCTION__); } int ideprobe_init (void) { - unsigned int index; + unsigned int i; int probe[MAX_HWIFS]; - memset(probe, 0, MAX_HWIFS * sizeof(int)); - for (index = 0; index < MAX_HWIFS; ++index) - probe[index] = !ide_hwifs[index].present; + for (i = 0; i < MAX_HWIFS; ++i) + probe[i] = !ide_hwifs[i].present; /* * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports */ - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - channel_probe(&ide_hwifs[index]); - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - channel_init(&ide_hwifs[index]); + for (i = 0; i < MAX_HWIFS; ++i) + if (probe[i]) + channel_probe(&ide_hwifs[i]); + for (i = 0; i < MAX_HWIFS; ++i) + if (probe[i]) + channel_init(&ide_hwifs[i]); + return 0; } diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide-tape.c Sun May 5 20:39:49 2002 @@ -2058,7 +2058,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - if (drive->channel->udma(ide_dma_end, drive, NULL)) { + if (udma_stop(drive)) { /* * A DMA error is sometimes expected. For example, * if the tape is crossing a filemark during a @@ -2132,7 +2132,8 @@ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - drive->channel->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); + return ide_stopped; } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -2309,11 +2310,15 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); - (void) drive->channel->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); } - if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok = !drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq); -#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) { + if (test_bit (PC_WRITING, &pc->flags)) + dma_ok = !udma_write(drive, rq); + else + dma_ok = !udma_read(drive, rq); + } +#endif if (IDE_CONTROL_REG) OUT_BYTE (drive->ctl, IDE_CONTROL_REG); @@ -2324,7 +2329,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); - (void) drive->channel->udma(ide_dma_begin, drive, NULL); + udma_start(drive, rq); } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/ide-taskfile.c Sun May 5 20:39:50 2002 @@ -130,12 +130,12 @@ } #endif -static void ata_read_16(ide_drive_t *drive, void *buffer, unsigned int wcount) +static void ata_read_16(struct ata_device *drive, void *buffer, unsigned int wcount) { insw(IDE_DATA_REG, buffer, wcount<<1); } -static void ata_write_16(ide_drive_t *drive, void *buffer, unsigned int wcount) +static void ata_write_16(struct ata_device *drive, void *buffer, unsigned int wcount) { outsw(IDE_DATA_REG, buffer, wcount<<1); } @@ -143,7 +143,7 @@ /* * This is used for most PIO data transfers *from* the device. */ -void ata_read(ide_drive_t *drive, void *buffer, unsigned int wcount) +void ata_read(struct ata_device *drive, void *buffer, unsigned int wcount) { int io_32bit; @@ -178,7 +178,7 @@ /* * This is used for most PIO data transfers *to* the device interface. */ -void ata_write(ide_drive_t *drive, void *buffer, unsigned int wcount) +void ata_write(struct ata_device *drive, void *buffer, unsigned int wcount) { int io_32bit; @@ -202,7 +202,7 @@ ata_write_slow(drive, buffer, wcount); else #endif - ata_write_16(drive, buffer, wcount<<1); + ata_write_16(drive, buffer, wcount); } } @@ -213,7 +213,7 @@ * so if an odd bytecount is specified, be sure that there's at least one * extra byte allocated for the buffer. */ -void atapi_read(ide_drive_t *drive, void *buffer, unsigned int bytecount) +void atapi_read(struct ata_device *drive, void *buffer, unsigned int bytecount) { if (drive->channel->atapi_read) { drive->channel->atapi_read(drive, buffer, bytecount); @@ -233,7 +233,7 @@ insw(IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); } -void atapi_write(ide_drive_t *drive, void *buffer, unsigned int bytecount) +void atapi_write(struct ata_device *drive, void *buffer, unsigned int bytecount) { if (drive->channel->atapi_write) { drive->channel->atapi_write(drive, buffer, bytecount); @@ -256,11 +256,11 @@ /* * Needed for PCI irq sharing */ -int drive_is_ready(ide_drive_t *drive) +int drive_is_ready(struct ata_device *drive) { byte stat = 0; if (drive->waiting_for_dma) - return drive->channel->udma(ide_dma_test_irq, drive, NULL); + return udma_irq_status(drive); #if 0 /* need to guarantee 400ns since last command was issued */ udelay(1); @@ -290,7 +290,7 @@ * Stuff the first sector(s) by implicitly calling the handler driectly * therafter. */ -void ata_poll_drive_ready(ide_drive_t *drive) +void ata_poll_drive_ready(struct ata_device *drive) { int i; @@ -399,7 +399,7 @@ return ide_started; } -ide_startstop_t ata_taskfile(ide_drive_t *drive, +ide_startstop_t ata_taskfile(struct ata_device *drive, struct ata_taskfile *args, struct request *rq) { struct hd_driveid *id = drive->id; @@ -456,11 +456,33 @@ if (args->prehandler != NULL) return args->prehandler(drive, rq); } else { - /* for dma commands we down set the handler */ - if (drive->using_dma && - !(drive->channel->udma(((args->taskfile.command == WIN_WRITEDMA) - || (args->taskfile.command == WIN_WRITEDMA_EXT)) - ? ide_dma_write : ide_dma_read, drive, rq))); + /* + * FIXME: this is a gross hack, need to unify tcq dma proc and + * regular dma proc -- basically split stuff that needs to act + * on a request from things like ide_dma_check etc. + */ + + if (!drive->using_dma) + return ide_started; + + /* for dma commands we don't set the handler */ + if (args->taskfile.command == WIN_WRITEDMA + || args->taskfile.command == WIN_WRITEDMA_EXT) + udma_write(drive, rq); + else if (args->taskfile.command == WIN_READDMA + || args->taskfile.command == WIN_READDMA_EXT) + udma_read(drive, rq); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + else if (args->taskfile.command == WIN_WRITEDMA_QUEUED + || args->taskfile.command == WIN_WRITEDMA_QUEUED_EXT + || args->taskfile.command == WIN_READDMA_QUEUED + || args->taskfile.command == WIN_READDMA_QUEUED_EXT) + return udma_tcq_taskfile(drive, rq); +#endif + else { + printk("ata_taskfile: unknown command %x\n", args->taskfile.command); + return ide_stopped; + } } return ide_started; @@ -523,7 +545,7 @@ ide__sti(); /* local CPU only */ if (!OK_STAT(stat = GET_STAT(), READY_STAT, BAD_STAT)) { - /* Keep quite for NOP becouse they are expected to fail. */ + /* Keep quiet for NOP because it is expected to fail. */ if (args && args->taskfile.command != WIN_NOP) return ide_error(drive, "task_no_data_intr", stat); } @@ -872,7 +894,7 @@ } } -int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *args, byte *buf) +int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *args, byte *buf) { struct request rq; @@ -898,7 +920,7 @@ * interface. */ -int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) +int ide_cmd_ioctl(struct ata_device *drive, unsigned long arg) { int err = 0; u8 vals[4]; diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ide.c Sun May 5 20:39:49 2002 @@ -1,15 +1,19 @@ -/* - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 1994-1998,2002 Linus Torvalds and authors: * - * Mostly written by Mark Lord - * and Gadi Oxman - * and Andre Hedrick + * Mark Lord + * Gadi Oxman + * Andre Hedrick + * Jens Axboe + * Marcin Dalecki * * See linux/MAINTAINERS for address of current maintainer. * - * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15). - * There can be up to two drives per interface, as per the ATA-2 spec. + * This is the basic common code of the ATA interface drivers. + * + * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 + * & 15). There can be up to two drives per interface, as per the ATA-7 spec. * * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64 * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64 @@ -17,102 +21,15 @@ * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64 * ... * - * From hd.c: - * | - * | It traverses the request-list, using interrupts to jump between functions. - * | As nearly all functions can be called within interrupts, we may not sleep. - * | Special care is recommended. Have Fun! - * | - * | modified by Drew Eckhardt to check nr of hd's from the CMOS. - * | - * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * | in the early extended-partition checks and added DM partitions. - * | - * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). - * | - * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * | and general streamlining by Mark Lord (mlord@pobox.com). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@ieee.org) ("Mr. atdisk2") - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with - * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - * - * Version 1.0 ALPHA initial code, primary i/f working okay - * Version 1.3 BETA dual i/f on shared irq tested & working! - * Version 1.4 BETA added auto probing for irq(s) - * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms, - * ... - * Version 5.50 allow values as small as 20 for idebus= - * Version 5.51 force non io_32bit in drive_cmd_intr() - * change delay_10ms() to delay_50ms() to fix problems - * Version 5.52 fix incorrect invalidation of removable devices - * add "hdx=slow" command line option - * Version 5.60 start to modularize the driver; the disk and ATAPI - * drivers can be compiled as loadable modules. - * move IDE probe code to ide-probe.c - * move IDE disk code to ide-disk.c - * add support for generic IDE device subdrivers - * add m68k code from Geert Uytterhoeven - * probe all interfaces by default - * add ioctl to (re)probe an interface - * Version 6.00 use per device request queues - * attempt to optimize shared hwgroup performance - * add ioctl to manually adjust bandwidth algorithms - * add kerneld support for the probe module - * fix bug in ide_error() - * fix bug in the first ide_get_lock() call for Atari - * don't flush leftover data for ATAPI devices - * Version 6.01 clear hwgroup->active while the hwgroup sleeps - * support HDIO_GETGEO for floppies - * Version 6.02 fix ide_ack_intr() call - * check partition table on floppies - * Version 6.03 handle bad status bit sequencing in ide_wait_stat() - * Version 6.10 deleted old entries from this list of updates - * replaced triton.c with ide-dma.c generic PCI DMA - * added support for BIOS-enabled UltraDMA - * rename all "promise" things to "pdc4030" - * fix EZ-DRIVE handling on small disks - * Version 6.11 fix probe error in ide_scan_devices() - * fix ancient "jiffies" polling bugs - * mask all hwgroup interrupts on each irq entry - * Version 6.12 integrate ioctl and proc interfaces - * fix parsing of "idex=" command line parameter - * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com - * Version 6.14 fixed IRQ sharing among PCI devices - * Version 6.15 added SMP awareness to IDE drivers - * Version 6.16 fixed various bugs; even more SMP friendly - * Version 6.17 fix for newest EZ-Drive problem - * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" - * Version 6.19 Re-design for a UNIFORM driver for all platforms, - * model based on suggestions from Russell King and - * Geert Uytterhoeven - * Promise DC4030VL now supported. - * add support for ide6/ide7 - * delay_50ms() changed to ide_delay_50ms() and exported. - * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection. - * Added hdx=flash to allow for second flash disk - * detection w/o the hang loop. - * Added support for ide8/ide9 - * Added idex=ata66 for the quirky chipsets that are - * ATA-66 compliant, but have yet to determine a method - * of verification of the 80c cable presence. - * Specifically Promise's PDC20262 chipset. - * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old - * hat that clarified original low level driver design. - * Version 6.30 Added SMP support; fixed multmode issues. -ml - * Version 6.31 Debug Share INTR's and request queue streaming - * Native ATA-100 support - * Prep for Cascades Project - * Version 6.32 4GB highmem support for DMA, and mapping of those for - * PIO transfer (Jens Axboe) + * Contributors: * - * Some additional driver compile-time options are in ./include/linux/ide.h + * Drew Eckhardt + * Branko Lankester + * Mika Liljeberg + * Delman Lee + * Scott Snyder + * + * Some additional driver compile-time options are in */ #define VERSION "7.0.0" @@ -253,10 +170,7 @@ #endif } -/* - * Do not even *think* about calling this! - */ -static void init_hwif_data(struct ata_channel *hwif, unsigned int index) +static void init_hwif_data(struct ata_channel *ch, unsigned int index) { static const byte ide_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, @@ -266,30 +180,30 @@ unsigned int unit; hw_regs_t hw; - /* bulk initialize hwif & drive info with zeros */ - memset(hwif, 0, sizeof(struct ata_channel)); + /* bulk initialize channel & drive info with zeros */ + memset(ch, 0, sizeof(struct ata_channel)); memset(&hw, 0, sizeof(hw_regs_t)); /* fill in any non-zero initial values */ - hwif->index = index; - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); - memcpy(&hwif->hw, &hw, sizeof(hw)); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + ch->index = index; + ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &ch->irq); + memcpy(&ch->hw, &hw, sizeof(hw)); + memcpy(ch->io_ports, hw.io_ports, sizeof(hw.io_ports)); + ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_HD - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) - hwif->noprobe = 1; /* may be overridden by ide_setup() */ + if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA) + ch->noprobe = 1; /* may be overridden by ide_setup() */ #endif /* CONFIG_BLK_DEV_HD */ - hwif->major = ide_major[index]; - sprintf(hwif->name, "ide%d", index); - hwif->bus_state = BUSSTATE_ON; + ch->major = ide_major[index]; + sprintf(ch->name, "ide%d", index); + ch->bus_state = BUSSTATE_ON; for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &hwif->drives[unit]; + struct ata_device *drive = &ch->drives[unit]; drive->type = ATA_DISK; drive->select.all = (unit<<4)|0xa0; - drive->channel = hwif; + drive->channel = ch; drive->ctl = 0x08; drive->ready_stat = READY_STAT; drive->bad_wstat = BAD_W_STAT; @@ -312,7 +226,7 @@ * of the kernel (such as memory allocation) to be functioning yet. * * This is too bad, as otherwise we could dynamically allocate the - * ide_drive_t structs as needed, rather than always consuming memory + * ata_device structs as needed, rather than always consuming memory * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */ #define MAGIC_COOKIE 0x12345678 @@ -349,24 +263,29 @@ * At that time, we might also consider parameterizing the timeouts and retries, * since these are MUCH faster than mechanical drives. -M.Lord */ -int drive_is_flashcard (ide_drive_t *drive) +int drive_is_flashcard(struct ata_device *drive) { struct hd_driveid *id = drive->id; + int i; + + char *flashcards[] = { + "KODAK ATA_FLASH", + "Hitachi CV", + "SunDisk SDCFB", + "HAGIWARA HPC", + "LEXAR ATA_FLASH", + "ATA_FLASH" /* Simple Tech */ + }; if (drive->removable && id != NULL) { if (id->config == 0x848a) return 1; /* CompactFlash */ - if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ - || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ - || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ - || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */ - || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */ - || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */ - { - return 1; /* yes, it is a flash memory card */ - } + for (i = 0; i < ARRAY_SIZE(flashcards); i++) + if (!strncmp(id->model, flashcards[i], + strlen(flashcards[i]))) + return 1; } - return 0; /* no, it is not a flash memory card */ + return 0; } int __ide_end_request(struct ata_device *drive, struct request *rq, int uptodate, int nr_secs) @@ -392,12 +311,15 @@ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { drive->state = 0; - drive->channel->udma(ide_dma_on, drive, rq); + udma_enable(drive, 1, 1); } if (!end_that_request_first(rq, uptodate, nr_secs)) { add_blkdev_randomness(major(rq->rq_dev)); - blkdev_dequeue_request(rq); + if (!blk_rq_tagged(rq)) + blkdev_dequeue_request(rq); + else + blk_queue_end_tag(&drive->queue, rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; @@ -442,13 +364,13 @@ /* check the DMA crc count */ if (drive->crc_count) { - drive->channel->udma(ide_dma_off_quietly, drive, NULL); + udma_enable(drive, 0, 0); if ((drive->channel->speedproc) != NULL) drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive)); if (drive->current_speed >= XFER_SW_DMA_0) - drive->channel->udma(ide_dma_on, drive, NULL); + udma_enable(drive, 1, 1); } else - drive->channel->udma(ide_dma_off, drive, NULL); + udma_enable(drive, 0, 1); } /* @@ -529,7 +451,7 @@ } } -static ide_startstop_t do_reset1(ide_drive_t *, int); /* needed below */ +static ide_startstop_t do_reset1(struct ata_device *, int); /* needed below */ /* * Poll the interface for completion every 50ms during an ATAPI drive reset @@ -629,7 +551,7 @@ * for it, we set a timer to poll at 50ms intervals. */ -static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) +static ide_startstop_t do_reset1(struct ata_device *drive, int do_not_try_atapi) { unsigned int unit; unsigned long flags; @@ -697,7 +619,7 @@ return ide_started; } -static inline u32 read_24 (ide_drive_t *drive) +static inline u32 read_24(struct ata_device *drive) { return (IN_BYTE(IDE_HCYL_REG)<<16) | (IN_BYTE(IDE_LCYL_REG)<<8) | @@ -761,7 +683,7 @@ /* * Error reporting, in human readable form (luxurious, but a memory hog). */ -byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) +byte ide_dump_status(struct ata_device *drive, const char *msg, byte stat) { unsigned long flags; byte err = 0; @@ -853,7 +775,7 @@ * condition by reading a sector's worth of data from the drive. Of course, * this may not help if the drive is *waiting* for data from *us*. */ -static void try_to_flush_leftover_data (ide_drive_t *drive) +static void try_to_flush_leftover_data(struct ata_device *drive) { int i; @@ -870,7 +792,7 @@ /* * Take action based on the error returned by the drive. */ -ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, byte stat) +ide_startstop_t ide_error(struct ata_device *drive, const char *msg, byte stat) { struct request *rq; byte err; @@ -927,7 +849,7 @@ /* * Issue a simple drive command. The drive must be selected beforehand. */ -void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ata_handler_t handler) +void ide_cmd(struct ata_device *drive, byte cmd, byte nsect, ata_handler_t handler) { ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) @@ -972,7 +894,7 @@ * setting a timer to wake up at half second intervals thereafter, until * timeout is achieved, before timing out. */ -int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { +int ide_wait_stat(ide_startstop_t *startstop, struct ata_device *drive, byte good, byte bad, unsigned long timeout) { byte stat; int i; unsigned long flags; @@ -1016,7 +938,7 @@ /* * This initiates handling of a new I/O request. */ -static ide_startstop_t start_request(ide_drive_t *drive, struct request *rq) +static ide_startstop_t start_request(struct ata_device *drive, struct request *rq) { sector_t block; unsigned int minor = minor(rq->rq_dev); @@ -1164,7 +1086,7 @@ return ide_stopped; } -ide_startstop_t restart_request(ide_drive_t *drive) +ide_startstop_t restart_request(struct ata_device *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long flags; @@ -1183,7 +1105,7 @@ * This is used by a drive to give excess bandwidth back to the hwgroup by * sleeping for timeout jiffies. */ -void ide_stall_queue(ide_drive_t *drive, unsigned long timeout) +void ide_stall_queue(struct ata_device *drive, unsigned long timeout) { if (timeout > WAIT_WORSTCASE) timeout = WAIT_WORSTCASE; @@ -1258,7 +1180,7 @@ /* This device still wants to remain idle. */ - if (drive->sleep && time_after(jiffies, drive->sleep)) + if (drive->sleep && time_after(drive->sleep, jiffies)) continue; /* Take this device, if there is no device choosen thus far or @@ -1285,8 +1207,8 @@ * want to hog the cpu too much. */ - if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) - sleep = jiffies + WAIT_MIN_SLEEP; + if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) + sleep = jiffies + WAIT_MIN_SLEEP; #if 1 if (timer_pending(&channel->hwgroup->timer)) printk(KERN_ERR "ide_set_handler: timer already active\n"); @@ -1305,11 +1227,6 @@ } -/* Place holders for later expansion of functionality. - */ -#define ata_pending_commands(drive) (0) -#define ata_can_queue(drive) (1) - /* * Feed commands to a drive until it barfs. Called with ide_lock/DRIVE_LOCK * held and busy channel. @@ -1349,7 +1266,7 @@ * still a severe BUG! */ if (blk_queue_plugged(&drive->queue)) { - BUG(); + BUG_ON(!drive->using_tcq); break; } @@ -1485,18 +1402,11 @@ */ static void dma_timeout_retry(struct ata_device *drive, struct request *rq) { - struct ata_channel *ch = drive->channel; - /* * end current dma transaction */ - ch->udma(ide_dma_end, drive, rq); - - /* - * complain a little, later we might remove some of this verbosity - */ - printk("%s: timeout waiting for DMA\n", drive->name); - ch->udma(ide_dma_timeout, drive, rq); + udma_stop(drive); + udma_timeout(drive); /* * Disable dma for now, but remember that we did so because of @@ -1505,7 +1415,7 @@ */ drive->retry_pio++; drive->state = DMA_PIO_RETRY; - ch->udma(ide_dma_off_quietly, drive, rq); + udma_enable(drive, 0, 0); /* * un-busy drive etc (hwgroup->busy is cleared on return) and @@ -1593,7 +1503,7 @@ startstop = handler(drive, ch->hwgroup->rq); } else if (drive_is_ready(drive)) { if (drive->waiting_for_dma) - ch->udma(ide_dma_lostirq, drive, ch->hwgroup->rq); + udma_irq_lost(drive); (void) ide_ack_intr(ch); printk("%s: lost interrupt\n", drive->name); startstop = handler(drive, ch->hwgroup->rq); @@ -1761,17 +1671,18 @@ } else { printk("%s: %s: huh? expected NULL handler on exit\n", drive->name, __FUNCTION__); } - } + } else if (startstop == ide_released) + queue_commands(drive, ch->irq); out_lock: spin_unlock_irqrestore(&ide_lock, flags); } /* - * get_info_ptr() returns the (ide_drive_t *) for a given device number. + * get_info_ptr() returns the (struct ata_device *) for a given device number. * It returns NULL if the given device number does not match any present drives. */ -ide_drive_t *get_info_ptr(kdev_t i_rdev) +struct ata_device *get_info_ptr(kdev_t i_rdev) { unsigned int major = major(i_rdev); int h; @@ -2099,25 +2010,13 @@ if (ch->straight8) { release_region(ch->io_ports[IDE_DATA_OFFSET], 8); } else { - if (ch->io_ports[IDE_DATA_OFFSET]) - release_region(ch->io_ports[IDE_DATA_OFFSET], 1); - if (ch->io_ports[IDE_ERROR_OFFSET]) - release_region(ch->io_ports[IDE_ERROR_OFFSET], 1); - if (ch->io_ports[IDE_NSECTOR_OFFSET]) - release_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1); - if (ch->io_ports[IDE_SECTOR_OFFSET]) - release_region(ch->io_ports[IDE_SECTOR_OFFSET], 1); - if (ch->io_ports[IDE_LCYL_OFFSET]) - release_region(ch->io_ports[IDE_LCYL_OFFSET], 1); - if (ch->io_ports[IDE_HCYL_OFFSET]) - release_region(ch->io_ports[IDE_HCYL_OFFSET], 1); - if (ch->io_ports[IDE_SELECT_OFFSET]) - release_region(ch->io_ports[IDE_SELECT_OFFSET], 1); - if (ch->io_ports[IDE_STATUS_OFFSET]) - release_region(ch->io_ports[IDE_STATUS_OFFSET], 1); + for (i = 0; i < 8; i++) + if (ch->io_ports[i]) + release_region(ch->io_ports[i], 1); } if (ch->io_ports[IDE_CONTROL_OFFSET]) release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1); +/* FIXME: check if we can remove this ifdef */ #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (ch->io_ports[IDE_IRQ_OFFSET]) release_region(ch->io_ports[IDE_IRQ_OFFSET], 1); @@ -2216,12 +2115,18 @@ ch->intrproc = old.intrproc; ch->maskproc = old.maskproc; ch->quirkproc = old.quirkproc; - ch->rwproc = old.rwproc; ch->ata_read = old.ata_read; ch->ata_write = old.ata_write; ch->atapi_read = old.atapi_read; ch->atapi_write = old.atapi_write; - ch->udma = old.udma; + ch->XXX_udma = old.XXX_udma; + ch->udma_start = old.udma_start; + ch->udma_stop = old.udma_stop; + ch->udma_read = old.udma_read; + ch->udma_write = old.udma_write; + ch->udma_irq_status = old.udma_irq_status; + ch->udma_timeout = old.udma_timeout; + ch->udma_irq_lost = old.udma_irq_lost; ch->busproc = old.busproc; ch->bus_state = old.bus_state; ch->dma_base = old.dma_base; @@ -2259,24 +2164,18 @@ int i; for (i = 0; i < IDE_NR_PORTS; i++) { - if (offsets[i] == -1) { - switch(i) { - case IDE_CONTROL_OFFSET: - hw->io_ports[i] = ctrl; - break; -#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) - case IDE_IRQ_OFFSET: - hw->io_ports[i] = intr; - break; -#endif - default: - hw->io_ports[i] = 0; - break; - } - } else { + if (offsets[i] != -1) hw->io_ports[i] = base + offsets[i]; - } + else + hw->io_ports[i] = 0; } + if (offsets[IDE_CONTROL_OFFSET] == -1) + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl; +/* FIMXE: check if we can remove this ifdef */ +#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) + if (offsets[IDE_IRQ_OFFSET] == -1) + hw->io_ports[IDE_IRQ_OFFSET] = intr; +#endif hw->irq = irq; hw->dma = NO_DMA; hw->ack_intr = ack_intr; @@ -2348,7 +2247,7 @@ return ide_register_hw(&hw, NULL); } -void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) +void ide_add_setting(struct ata_device *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = &drive->settings; ide_settings_t *setting = NULL; @@ -2375,7 +2274,7 @@ kfree(setting); } -void ide_remove_setting (ide_drive_t *drive, char *name) +void ide_remove_setting(struct ata_device *drive, char *name) { ide_settings_t **p = &drive->settings, *setting; @@ -2388,7 +2287,7 @@ kfree(setting); } -static void auto_remove_settings (ide_drive_t *drive) +static void auto_remove_settings(struct ata_device *drive) { ide_settings_t *setting; repeat: @@ -2402,10 +2301,10 @@ } } -int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) +int ide_read_setting(struct ata_device *drive, ide_settings_t *setting) { - int val = -EINVAL; - unsigned long flags; + int val = -EINVAL; + unsigned long flags; if ((setting->rw & SETTING_READ)) { spin_lock_irqsave(&ide_lock, flags); @@ -2426,7 +2325,7 @@ return val; } -int ide_spin_wait_hwgroup (ide_drive_t *drive) +int ide_spin_wait_hwgroup(struct ata_device *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); @@ -2454,7 +2353,7 @@ * to the driver to change settings, and then wait on a semaphore for completion. * The current scheme of polling is kludgey, though safe enough. */ -int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) +int ide_write_setting(struct ata_device *drive, ide_settings_t *setting, int val) { int i; u32 *p; @@ -2499,18 +2398,19 @@ return 0; } -static int set_using_dma(ide_drive_t *drive, int arg) +static int set_using_dma(struct ata_device *drive, int arg) { if (!drive->driver) return -EPERM; - if (!drive->id || !(drive->id->capability & 1) || !drive->channel->udma) + + if (!drive->id || !(drive->id->capability & 1) || !drive->channel->XXX_udma) return -EPERM; - if (drive->channel->udma(arg ? ide_dma_on : ide_dma_off, drive, NULL)) - return -EIO; + + udma_enable(drive, arg, 1); return 0; } -static int set_pio_mode(ide_drive_t *drive, int arg) +static int set_pio_mode(struct ata_device *drive, int arg) { struct request rq; @@ -2528,7 +2428,7 @@ return 0; } -void ide_add_generic_settings (ide_drive_t *drive) +void ide_add_generic_settings(struct ata_device *drive) { /* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */ ide_add_setting(drive, "io_32bit", drive->channel->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->channel->io_32bit, set_io_32bit); @@ -2563,7 +2463,7 @@ static int ide_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0, major, minor; - ide_drive_t *drive; + struct ata_device *drive; struct request rq; kdev_t dev; ide_settings_t *setting; @@ -2717,7 +2617,7 @@ static int ide_check_media_change (kdev_t i_rdev) { - ide_drive_t *drive; + struct ata_device *drive; int res = 0; /* not changed */ drive = get_info_ptr(i_rdev); @@ -2861,7 +2761,7 @@ * "hdx=flash" : allows for more than one ata_flash disk to be * registered. In most cases, only one device * will be present. - * "hdx=scsi" : the return of the ide-scsi flag, this is useful for + * "hdx=ide-scsi" : the return of the ide-scsi flag, this is useful for * allowwing ide-floppy, ide-tape, and ide-cdrom|writers * to use ide-scsi emulation on a device specific option. * "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, @@ -2915,7 +2815,7 @@ { int i, vals[3]; struct ata_channel *hwif; - ide_drive_t *drive; + struct ata_device *drive; unsigned int hw, unit; const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); const char max_hwif = '0' + (MAX_HWIFS - 1); @@ -2928,14 +2828,14 @@ strncmp(s,"hd",2)) /* hdx= & hdxlun= */ return 0; - printk("ide_setup: %s", s); + printk(KERN_INFO "ide_setup: %s", s); init_ide_data (); #ifdef CONFIG_BLK_DEV_IDEDOUBLER if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; - printk(" : Enabled support for IDE doublers\n"); + printk(KERN_INFO" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 1; @@ -2943,7 +2843,7 @@ #endif if (!strcmp(s, "ide=nodma")) { - printk("IDE: Prevented DMA\n"); + printk(KERN_INFO "ATA: Prevented DMA\n"); noautodma = 1; return 1; @@ -3231,7 +3131,7 @@ /* * Lookup ATA devices, which requested a particular driver. */ -ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n) +struct ata_device *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n) { unsigned int unit, index, i; @@ -3258,7 +3158,7 @@ /* * This is in fact registering a drive not a driver. */ -int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver) +int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driver) { unsigned long flags; @@ -3278,7 +3178,7 @@ restore_flags(flags); /* all CPUs */ /* FIXME: Check what this magic number is supposed to be about? */ if (drive->autotune != 2) { - if (drive->channel->udma) { + if (drive->channel->XXX_udma) { /* * Force DMAing for the beginning of the check. Some @@ -3288,8 +3188,11 @@ * PARANOIA!!! */ - drive->channel->udma(ide_dma_off_quietly, drive, NULL); - drive->channel->udma(ide_dma_check, drive, NULL); + udma_enable(drive, 0, 0); + drive->channel->XXX_udma(drive); +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + udma_tcq_enable(drive, 1); +#endif } /* Only CD-ROMs and tape drives support DSC overlap. But only @@ -3322,7 +3225,7 @@ * * FIXME: Check whatever we maybe don't call it twice!. */ -int ide_unregister_subdriver(ide_drive_t *drive) +int ide_unregister_subdriver(struct ata_device *drive) { unsigned long flags; @@ -3497,7 +3400,7 @@ { int h; - printk(KERN_INFO "Uniform Multi-Platform E-IDE driver ver.:" VERSION "\n"); + printk(KERN_INFO "ATA/ATAPI driver v" VERSION "\n"); ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); @@ -3519,7 +3422,7 @@ system_bus_speed = 33; #endif - printk("ide: system bus speed %dMHz\n", system_bus_speed); + printk(KERN_INFO "ATA: system bus speed %dMHz\n", system_bus_speed); init_ide_data (); @@ -3640,27 +3543,23 @@ MODULE_PARM(options,"s"); MODULE_LICENSE("GPL"); -static void __init parse_options (char *line) +static int __init init_ata(void) { - char *next = line; - if (line == NULL || !*line) - return; - while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) - *next++ = 0; - if (!ide_setup(line)) - printk ("Unknown option '%s'\n", line); - } -} + if (options != NULL && *options) { + char *next = options; -static int __init init_ata (void) -{ - parse_options(options); + while ((options = next) != NULL) { + if ((next = strchr(options,' ')) != NULL) + *next++ = 0; + if (!ide_setup(options)) + printk(KERN_ERR "Unknown option '%s'\n", options); + } + } return ata_module_init(); } -static void __exit cleanup_ata (void) +static void __exit cleanup_ata(void) { int h; diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c --- a/drivers/ide/ns87415.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/ns87415.c Sun May 5 20:39:49 2002 @@ -82,35 +82,57 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA -static int ns87415_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) + +static int ns87415_udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + drive->waiting_for_dma = 0; + dma_stat = inb(ch->dma_base+2); + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + outb(inb(dma_base)|6, dma_base); /* from ERRATA: clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* and free any DMA resources */ + + return (dma_stat & 7) != 4; /* verify good DMA status */ + +} + +static int ns87415_udma_read(struct ata_device *drive, struct request *rq) { - struct ata_channel *hwif = drive->channel; - byte dma_stat; + ns87415_prepare_drive(drive, 1); /* select DMA xfer */ - switch (func) { - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - drive->waiting_for_dma = 0; - dma_stat = inb(hwif->dma_base+2); - outb(inb(hwif->dma_base)&~1, hwif->dma_base); /* stop DMA */ - outb(inb(hwif->dma_base)|6, hwif->dma_base); /* from ERRATA: clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* and free any DMA resources */ - return (dma_stat & 7) != 4; /* verify good DMA status */ - case ide_dma_write: - case ide_dma_read: - ns87415_prepare_drive(drive, 1); /* select DMA xfer */ - if (!ide_dmaproc(func, drive, rq)) /* use standard DMA stuff */ - return 0; - ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ - return 1; - case ide_dma_check: - if (drive->type != ATA_DISK) - return ide_dmaproc(ide_dma_off_quietly, drive, rq); - /* Fallthrough... */ - default: - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + if (!ata_do_udma(1, drive, rq)) /* use standard DMA stuff */ + return 0; + + ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ + + return 1; +} + +static int ns87415_udma_write(struct ata_device *drive, struct request *rq) +{ + ns87415_prepare_drive(drive, 1); /* select DMA xfer */ + + if (!ata_do_udma(0, drive, rq)) /* use standard DMA stuff */ + return 0; + + ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ + + return 1; +} + +static int ns87415_dmaproc(struct ata_device *drive) +{ + if (drive->type != ATA_DISK) { + udma_enable(drive, 0, 0); + + return 0; } + return XXX_ide_dmaproc(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif void __init ide_init_ns87415(struct ata_channel *hwif) { @@ -205,8 +227,12 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) - hwif->udma = ns87415_dmaproc; + if (hwif->dma_base) { + hwif->udma_stop = ns87415_udma_stop; + hwif->udma_read = ns87415_udma_read; + hwif->udma_write = ns87415_udma_write; + hwif->XXX_udma = ns87415_dmaproc; + } #endif hwif->selectproc = &ns87415_selectproc; diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c --- a/drivers/ide/pdc202xx.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/pdc202xx.c Sun May 5 20:39:50 2002 @@ -829,7 +829,7 @@ if (jumpbit) { if (drive->type != ATA_DISK) - return ide_dma_off_quietly; + return 0; if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ OUT_BYTE((iordy + adj), indexreg); OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); @@ -873,13 +873,13 @@ pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); break; default: - return ide_dma_off; + return 0; } chipset_is_set: if (drive->type != ATA_DISK) - return ide_dma_off_quietly; + return 0; pci_read_config_byte(dev, (drive_pci), &AP); if (id->capability & 4) /* IORDY_EN */ @@ -907,39 +907,41 @@ /* restore original pci-config space */ if (!jumpbit) pci_write_config_dword(dev, drive_pci, drive_conf); - return ide_dma_off_quietly; + return 0; } outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) hwif->speedproc(drive, speed); - return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : - ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 14) & 3) ? 1 : + ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; struct ata_channel *hwif = drive->channel; - ide_dma_action_t dma_func = ide_dma_off_quietly; + int on = 0; + int verbose = 1; if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + on = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -947,29 +949,32 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: (void) config_chipset_for_pio(drive, 5); } - return drive->channel->udma(dma_func, drive, NULL); + udma_enable(drive, on, verbose); + + return 0; } int pdc202xx_quirkproc (ide_drive_t *drive) @@ -977,21 +982,15 @@ return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); } -/* - * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - */ -int pdc202xx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int pdc202xx_udma_start(struct ata_device *drive, struct request *rq) { - byte dma_stat = 0; - byte sc1d = 0; - byte newchip = 0; - byte clock = 0; - byte hardware48hack = 0; - struct ata_channel *hwif = drive->channel; - struct pci_dev *dev = hwif->pci_dev; + u8 clock = 0; + u8 hardware48hack = 0; + struct ata_channel *ch = drive->channel; + struct pci_dev *dev = ch->pci_dev; unsigned long high_16 = pci_resource_start(dev, 4); - unsigned long atapi_reg = high_16 + (hwif->unit ? 0x24 : 0x00); - unsigned long dma_base = hwif->dma_base; + unsigned long atapi_reg = high_16 + (ch->unit ? 0x24 : 0x00); + switch (dev->device) { case PCI_DEVICE_ID_PROMISE_20275: @@ -999,7 +998,6 @@ case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268R: case PCI_DEVICE_ID_PROMISE_20268: - newchip = 1; break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: @@ -1010,59 +1008,136 @@ break; } - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_begin: - /* Note that this is done *after* the cmd has - * been issued to the drive, as per the BM-IDE spec. - * The Promise Ultra33 doesn't work correctly when - * we do this part before issuing the drive cmd. - */ - if ((drive->addressing) && (hardware48hack)) { - struct request *rq = HWGROUP(drive)->rq; - unsigned long word_count = 0; - - outb(clock|(hwif->unit ? 0x08 : 0x02), high_16 + 0x11); - word_count = (rq->nr_sectors << 8); - word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; - outl(word_count, atapi_reg); - } + if ((drive->addressing) && (hardware48hack)) { + unsigned long word_count = 0; + + outb(clock|(ch->unit ? 0x08 : 0x02), high_16 + 0x11); + word_count = (rq->nr_sectors << 8); + word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; + outl(word_count, atapi_reg); + } + + /* Note that this is done *after* the cmd has been issued to the drive, + * as per the BM-IDE spec. The Promise Ultra33 doesn't work correctly + * when we do this part before issuing the drive cmd. + */ + + outb(inb(ch->dma_base) | 1, ch->dma_base); /* start DMA */ + + return 0; +} + +int pdc202xx_udma_stop(struct ata_device *drive) +{ + u8 newchip = 0; + u8 clock = 0; + u8 hardware48hack = 0; + struct ata_channel *ch = drive->channel; + struct pci_dev *dev = ch->pci_dev; + unsigned long high_16 = pci_resource_start(dev, 4); + unsigned long atapi_reg = high_16 + (ch->unit ? 0x24 : 0x00); + unsigned long dma_base = ch->dma_base; + u8 dma_stat; + + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268R: + case PCI_DEVICE_ID_PROMISE_20268: + newchip = 1; break; - case ide_dma_end: - if ((drive->addressing) && (hardware48hack)) { - outl(0, atapi_reg); /* zero out extra */ - clock = IN_BYTE(high_16 + 0x11); - OUT_BYTE(clock & ~(hwif->unit ? 0x08:0x02), high_16 + 0x11); - } + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20262: + hardware48hack = 1; + clock = IN_BYTE(high_16 + 0x11); + default: break; - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = IN_BYTE(dma_base+2); - if (newchip) - return (dma_stat & 4) == 4; - - sc1d = IN_BYTE(high_16 + 0x001d); - if (drive->channel->unit) { - if ((sc1d & 0x50) == 0x50) goto somebody_else; - else if ((sc1d & 0x40) == 0x40) - return (dma_stat & 4) == 4; - } else { - if ((sc1d & 0x05) == 0x05) goto somebody_else; - else if ((sc1d & 0x04) == 0x04) - return (dma_stat & 4) == 4; - } -somebody_else: - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ - case ide_dma_lostirq: - case ide_dma_timeout: - if (drive->channel->resetproc != NULL) - drive->channel->resetproc(drive); + } + if ((drive->addressing) && (hardware48hack)) { + outl(0, atapi_reg); /* zero out extra */ + clock = IN_BYTE(high_16 + 0x11); + OUT_BYTE(clock & ~(ch->unit ? 0x08:0x02), high_16 + 0x11); + } + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* purge DMA mappings */ + + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ +} + +static int pdc202xx_udma_irq_status(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + u8 dma_stat = 0; + u8 sc1d = 0; + u8 newchip = 0; + u8 clock = 0; + u8 hardware48hack = 0; + struct pci_dev *dev = ch->pci_dev; + unsigned long high_16 = pci_resource_start(dev, 4); + unsigned long dma_base = ch->dma_base; + + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268R: + case PCI_DEVICE_ID_PROMISE_20268: + newchip = 1; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20262: + hardware48hack = 1; + clock = IN_BYTE(high_16 + 0x11); default: break; } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + + dma_stat = IN_BYTE(dma_base + 2); + if (newchip) + return (dma_stat & 4) == 4; + + sc1d = IN_BYTE(high_16 + 0x001d); + if (ch->unit) { + if ((sc1d & 0x50) == 0x50) goto somebody_else; + else if ((sc1d & 0x40) == 0x40) + return (dma_stat & 4) == 4; + } else { + if ((sc1d & 0x05) == 0x05) goto somebody_else; + else if ((sc1d & 0x04) == 0x04) + return (dma_stat & 4) == 4; + } +somebody_else: + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ +} + +static void pdc202xx_udma_timeout(struct ata_device *drive) +{ + if (!drive->channel->resetproc) + return; + /* Assume naively that resetting the drive may help. */ + drive->channel->resetproc(drive); +} + +static void pdc202xx_udma_irq_lost(struct ata_device *drive) +{ + if (!drive->channel->resetproc) + return; + /* Assume naively that resetting the drive may help. */ + drive->channel->resetproc(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + +static int pdc202xx_dmaproc(struct ata_device *drive) +{ + return config_drive_xfer_rate(drive); +} +#endif void pdc202xx_new_reset (ide_drive_t *drive) { @@ -1268,7 +1343,12 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { - hwif->udma = pdc202xx_dmaproc; + hwif->udma_start = pdc202xx_udma_start; + hwif->udma_stop = pdc202xx_udma_stop; + hwif->udma_irq_status = pdc202xx_udma_irq_status; + hwif->udma_irq_lost = pdc202xx_udma_irq_lost; + hwif->udma_timeout = pdc202xx_udma_timeout; + hwif->XXX_udma = pdc202xx_dmaproc; hwif->highmem = 1; if (!noautodma) hwif->autodma = 1; diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c --- a/drivers/ide/pdcadma.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/pdcadma.c Sun May 5 20:39:49 2002 @@ -58,15 +58,11 @@ /* * This initiates/aborts (U)DMA read/write operations on a drive. */ -int pdcadma_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int pdcadma_dmaproc(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - func = ide_dma_off_quietly; - default: - break; - } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + udma_enable(drive, 0, 0); + + return 0; } #endif @@ -96,7 +92,7 @@ // hwif->speedproc = &pdcadma_tune_chipset; // if (hwif->dma_base) { -// hwif->dmaproc = &pdcadma_dmaproc; +// hwif->XXX_dmaproc = &pdcadma_dmaproc; // hwif->autodma = 1; // } } diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c --- a/drivers/ide/piix.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/piix.c Sun May 5 20:39:49 2002 @@ -376,38 +376,26 @@ #ifdef CONFIG_BLK_DEV_IDEDMA -/* - * piix_dmaproc() is a callback from upper layers that can do - * a lot, but we use it for DMA/PIO tuning only, delegating everything - * else to the default ide_dmaproc(). - */ - -int piix_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +int piix_dmaproc(struct ata_device *drive) { + short w80 = drive->channel->udma_four; - if (func == ide_dma_check) { - - short w80 = drive->channel->udma_four; - - short speed = ata_timing_mode(drive, - XFER_PIO | XFER_EPIO | + short speed = ata_timing_mode(drive, + XFER_PIO | XFER_EPIO | (piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA | (piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) | (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) | (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0) | (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_133 ? XFER_UDMA_133 : 0)))); - piix_set_drive(drive, speed); + piix_set_drive(drive, speed); - func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO) - ? ide_dma_on : ide_dma_off_quietly; + udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0); - } - - return ide_dmaproc(func, drive, rq); + return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * The initialization callback. Here we determine the IDE chip type @@ -566,13 +554,13 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->highmem = 1; - hwif->udma = piix_dmaproc; -#ifdef CONFIG_IDEDMA_AUTO + hwif->XXX_udma = piix_dmaproc; +# ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; -#endif +# endif } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif } /* diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c --- a/drivers/ide/serverworks.c Sun May 5 20:39:50 2002 +++ b/drivers/ide/serverworks.c Sun May 5 20:39:50 2002 @@ -424,31 +424,33 @@ (void) svwks_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } -static int config_drive_xfer_rate (ide_drive_t *drive) +static int config_drive_xfer_rate(struct ata_device *drive) { struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; + int on = 1; + int verbose = 1; if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive); + on = config_chipset_for_dma(drive); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -456,76 +458,82 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive); + if (!on) goto no_dma_set; } - } else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) { + } else if (udma_white_list(drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: config_chipset_for_pio(drive); } - return drive->channel->udma(dma_func, drive, NULL); + + udma_enable(drive, on, verbose); + + return 0; } -static int svwks_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int svwks_udma_stop(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_end: - { - struct ata_channel *hwif = drive->channel; - unsigned long dma_base = hwif->dma_base; + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + u8 dma_stat; - if(inb(dma_base+0x02)&1) - { + if(inb(dma_base+0x02)&1) + { #if 0 - int i; - printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n"); - for(i=0;i<10;i++) - { - if(!(inb(dma_base+0x02)&1)) - { - printk(KERN_ERR "OSB4 now finished.\n"); - break; - } - udelay(5); - } + int i; + printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n"); + for(i=0;i<10;i++) + { + if(!(inb(dma_base+0x02)&1)) + { + printk(KERN_ERR "OSB4 now finished.\n"); + break; + } + udelay(5); + } #endif - printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n"); - printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n"); - printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n"); + printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n"); + printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n"); + printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n"); #if 0 - /* Panic might sys_sync -> death by corrupt disk */ - panic("OSB4: continuing might cause disk corruption.\n"); + /* Panic might sys_sync -> death by corrupt disk */ + panic("OSB4: continuing might cause disk corruption.\n"); #else - printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n"); - while(1) - cpu_relax(); + printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n"); + while(1) + cpu_relax(); #endif - } - /* and drop through */ - } - default: - break; } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive, rq); + + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + udma_destroy_table(ch); /* purge DMA mappings */ + + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + +static int svwks_dmaproc(struct ata_device *drive) +{ + return config_drive_xfer_rate(drive); +} +#endif unsigned int __init pci_init_svwks(struct pci_dev *dev) { @@ -645,7 +653,8 @@ if (!noautodma) hwif->autodma = 1; #endif - hwif->udma = svwks_dmaproc; + hwif->udma_stop = svwks_udma_stop; + hwif->XXX_udma = svwks_dmaproc; hwif->highmem = 1; } else { hwif->autodma = 0; diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c --- a/drivers/ide/sis5513.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/sis5513.c Sun May 5 20:39:49 2002 @@ -556,7 +556,7 @@ case 1: drive_pci = 0x42; break; case 2: drive_pci = 0x44; break; case 3: drive_pci = 0x46; break; - default: return ide_dma_off; + default: return 0; } #ifdef BROKEN_LEVEL @@ -663,39 +663,41 @@ else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; else - return ((int) ide_dma_off_quietly); + return 0; outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); sis5513_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 7) ? 1 : + ((id->dma_ultra >> 8) & 7) ? 1 : + ((id->dma_mword >> 8) & 7) ? 1 : + ((id->dma_1word >> 8) & 7) ? 1 : + 0); } static int config_drive_xfer_rate (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_off_quietly; + struct hd_driveid *id = drive->id; + int on = 0; + int verbose = 1; config_chipset_for_pio(drive, 5); if (id && (id->capability & 1) && drive->channel->autodma) { /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; if (id->field_valid & 4) { if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + on = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) + (!on)) goto try_dma_modes; } } else if (id->field_valid & 2) { @@ -703,43 +705,40 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } - } else if ((ide_dmaproc(ide_dma_good_drive, drive, NULL)) && + } else if ((udma_white_list(drive)) && (id->eide_dma_time > 150)) { /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) + on = config_chipset_for_dma(drive, 0); + if (!on) goto no_dma_set; } else { goto fast_ata_pio; } } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - dma_func = ide_dma_off_quietly; + on = 0; + verbose = 0; no_dma_set: (void) config_chipset_for_pio(drive, 5); } - return drive->channel->udma(dma_func, drive, NULL); + udma_enable(drive, on, verbose); + + return 0; } -/* initiates/aborts (U)DMA read/write operations on a drive. */ -int sis5513_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int sis5513_dmaproc(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - return config_drive_xfer_rate(drive); - default: - break; - } - return ide_dmaproc(func, drive, rq); /* use standard DMA stuff */ + config_drive_art_rwp(drive); + config_art_rwp_pio(drive, 5); + + return config_drive_xfer_rate(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* Chip detection and general config */ unsigned int __init pci_init_sis5513(struct pci_dev *dev) @@ -852,7 +851,7 @@ if (chipset_family > ATA_16) { hwif->autodma = noautodma ? 0 : 1; hwif->highmem = 1; - hwif->udma = sis5513_dmaproc; + hwif->XXX_udma = sis5513_dmaproc; } else { #endif hwif->autodma = 0; diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c --- a/drivers/ide/sl82c105.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/sl82c105.c Sun May 5 20:39:49 2002 @@ -116,7 +116,7 @@ */ static int sl82c105_check_drive(ide_drive_t *drive) { - ide_dma_action_t dma_func = ide_dma_off_quietly; + int on = 0; do { struct hd_driveid *id = drive->id; @@ -129,46 +129,39 @@ break; /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; + if (udma_black_list(drive)) { + on = 0; break; } if (id->field_valid & 2) { if (id->dma_mword & 7 || id->dma_1word & 7) - dma_func = ide_dma_on; + on = 1; break; } - if (ide_dmaproc(ide_dma_good_drive, drive)) { - dma_func = ide_dma_on; + if (udma_white_list(drive)) { + on = 1; break; } } while (0); + if (on) + config_for_dma(drive); + else + config_for_pio(drive, 4, 0); + + udma_enable(drive, on, 0); + - return drive->channel->dmaproc(dma_func, drive); + return 0; } /* * Our own dmaproc, only to intercept ide_dma_check */ -static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +static int sl82c105_dmaproc(struct ata_device *drive) { - switch (func) { - case ide_dma_check: - return sl82c105_check_drive(drive); - case ide_dma_on: - if (config_for_dma(drive)) - func = ide_dma_off; - /* fall through */ - case ide_dma_off_quietly: - case ide_dma_off: - config_for_pio(drive, 4, 0); - break; - default: - break; - } - return ide_dmaproc(func, drive); + return sl82c105_check_drive(drive); } /* @@ -183,8 +176,8 @@ * We support 32-bit I/O on this interface, and it * doesn't have problems with interrupts. */ - drive->io_32bit = 1; - drive->unmask = 1; + drive->channel->io_32bit = 1; + drive->channel->unmask = 1; } /* @@ -252,10 +245,10 @@ } outb(dma_state, dma_base + 2); - hwif->dmaproc = NULL; + hwif->XXX_udma = NULL; ide_setup_dma(hwif, dma_base, 8); - if (hwif->dmaproc) - hwif->dmaproc = sl82c105_dmaproc; + if (hwif->XXX_udma) + hwif->XXX_udma = sl82c105_dmaproc; } /* diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/ide/tcq.c Sun May 5 20:39:50 2002 @@ -0,0 +1,635 @@ +/* + * Copyright (C) 2001, 2002 Jens Axboe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Support for the DMA queued protocol, which enables ATA disk drives to + * use tagged command queueing. + */ +#include +#include +#include +#include +#include +#include + +#include + +/* + * warning: it will be _very_ verbose if defined + */ +#undef IDE_TCQ_DEBUG + +#ifdef IDE_TCQ_DEBUG +#define TCQ_PRINTK printk +#else +#define TCQ_PRINTK(x...) +#endif + +/* + * use nIEN or not + */ +#undef IDE_TCQ_NIEN + +/* + * We are leaving the SERVICE interrupt alone, IBM drives have it + * on per default and it can't be turned off. Doesn't matter, this + * is the sane config. + */ +#undef IDE_TCQ_FIDDLE_SI + +static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq); +static ide_startstop_t service(struct ata_device *drive); + +static inline void drive_ctl_nien(struct ata_device *drive, int set) +{ +#ifdef IDE_TCQ_NIEN + if (IDE_CONTROL_REG) { + int mask = set ? 0x02 : 0x00; + + OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG); + } +#endif +} + +static ide_startstop_t tcq_nop_handler(struct ata_device *drive, struct request *rq) +{ + struct ata_taskfile *args = rq->special; + + ide__sti(); + ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); + kfree(args); + return ide_stopped; +} + +/* + * If we encounter _any_ error doing I/O to one of the tags, we must + * invalidate the pending queue. Clear the software busy queue and requeue + * on the request queue for restart. Issue a WIN_NOP to clear hardware queue. + */ +static void tcq_invalidate_queue(struct ata_device *drive) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + request_queue_t *q = &drive->queue; + struct ata_taskfile *args; + struct request *rq; + unsigned long flags; + + printk(KERN_INFO "ATA: %s: invalidating pending queue (%d)\n", drive->name, ata_pending_commands(drive)); + + spin_lock_irqsave(&ide_lock, flags); + + del_timer(&hwgroup->timer); + + if (test_bit(IDE_DMA, &hwgroup->flags)) + udma_stop(drive); + + blk_queue_invalidate_tags(q); + + drive->using_tcq = 0; + drive->queue_depth = 1; + clear_bit(IDE_BUSY, &hwgroup->flags); + clear_bit(IDE_DMA, &hwgroup->flags); + hwgroup->handler = NULL; + + /* + * Do some internal stuff -- we really need this command to be + * executed before any new commands are started. issue a NOP + * to clear internal queue on drive. + */ + args = kmalloc(sizeof(*args), GFP_ATOMIC); + if (!args) { + printk(KERN_ERR "ATA: %s: failed to issue NOP\n", drive->name); + goto out; + } + + rq = blk_get_request(&drive->queue, READ, GFP_ATOMIC); + if (!rq) + rq = blk_get_request(&drive->queue, WRITE, GFP_ATOMIC); + + /* + * blk_queue_invalidate_tags() just added back at least one command + * to the free list, so there _must_ be at least one free. + */ + BUG_ON(!rq); + + rq->special = args; + args->taskfile.command = WIN_NOP; + args->handler = tcq_nop_handler; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + + rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<request_fn(q); + spin_unlock_irqrestore(&ide_lock, flags); + printk(KERN_DEBUG "ATA: tcq_invalidate_queue: done\n"); +} + +static void ata_tcq_irq_timeout(unsigned long data) +{ + struct ata_device *drive = (struct ata_device *) data; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long flags; + + printk(KERN_ERR "ATA: %s: timeout waiting for interrupt...\n", __FUNCTION__); + + spin_lock_irqsave(&ide_lock, flags); + + if (test_and_set_bit(IDE_BUSY, &hwgroup->flags)) + printk(KERN_ERR "ATA: %s: hwgroup not busy\n", __FUNCTION__); + if (hwgroup->handler == NULL) + printk(KERN_ERR "ATA: %s: missing isr!\n", __FUNCTION__); + + spin_unlock_irqrestore(&ide_lock, flags); + + /* + * if pending commands, try service before giving up + */ + if (ata_pending_commands(drive) && (GET_STAT() & SERVICE_STAT)) + if (service(drive) == ide_started) + return; + + if (drive) + tcq_invalidate_queue(drive); +} + +static void set_irq(struct ata_device *drive, ata_handler_t *handler) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + + /* + * always just bump the timer for now, the timeout handling will + * have to be changed to be per-command + */ + hwgroup->timer.function = ata_tcq_irq_timeout; + hwgroup->timer.data = (unsigned long) hwgroup->XXX_drive; + mod_timer(&hwgroup->timer, jiffies + 5 * HZ); + + hwgroup->handler = handler; + spin_unlock_irqrestore(&ide_lock, flags); +} + +/* + * wait 400ns, then poll for busy_mask to clear from alt status + */ +#define IDE_TCQ_WAIT (10000) +static int wait_altstat(struct ata_device *drive, u8 *stat, u8 busy_mask) +{ + int i = 0; + + udelay(1); + + while ((*stat = GET_ALTSTAT()) & busy_mask) { + if (unlikely(i++ > IDE_TCQ_WAIT)) + return 1; + + udelay(10); + } + + return 0; +} + +static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *rq); + +/* + * issue SERVICE command to drive -- drive must have been selected first, + * and it must have reported a need for service (status has SERVICE_STAT set) + * + * Also, nIEN must be set as not to need protection against ide_dmaq_intr + */ +static ide_startstop_t service(struct ata_device *drive) +{ + struct request *rq; + u8 feat; + u8 stat; + int tag; + + TCQ_PRINTK("%s: started service\n", drive->name); + + /* + * Could be called with IDE_DMA in-progress from invalidate + * handler, refuse to do anything. + */ + if (test_bit(IDE_DMA, &HWGROUP(drive)->flags)) + return ide_stopped; + + /* + * need to select the right drive first... + */ + if (drive != HWGROUP(drive)->XXX_drive) { + SELECT_DRIVE(drive->channel, drive); + udelay(10); + } + + drive_ctl_nien(drive, 1); + + /* + * send SERVICE, wait 400ns, wait for BUSY_STAT to clear + */ + OUT_BYTE(WIN_QUEUED_SERVICE, IDE_COMMAND_REG); + + if (wait_altstat(drive, &stat, BUSY_STAT)) { + printk(KERN_ERR"%s: BUSY clear took too long\n", __FUNCTION__); + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + drive_ctl_nien(drive, 0); + + /* + * FIXME, invalidate queue + */ + if (stat & ERR_STAT) { + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + /* + * should not happen, a buggy device could introduce loop + */ + if ((feat = GET_FEAT()) & NSEC_REL) { + HWGROUP(drive)->rq = NULL; + printk("%s: release in service\n", drive->name); + return ide_stopped; + } + + tag = feat >> 3; + + TCQ_PRINTK("%s: stat %x, feat %x\n", __FUNCTION__, stat, feat); + + rq = blk_queue_tag_request(&drive->queue, tag); + if (!rq) { + printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag); + return ide_stopped; + } + + HWGROUP(drive)->rq = rq; + + /* + * we'll start a dma read or write, device will trigger + * interrupt to indicate end of transfer, release is not allowed + */ + TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat); + return udma_tcq_start(drive, rq); +} + +static ide_startstop_t check_service(struct ata_device *drive) +{ + u8 stat; + + TCQ_PRINTK("%s: %s\n", drive->name, __FUNCTION__); + + if (!ata_pending_commands(drive)) + return ide_stopped; + + if ((stat = GET_STAT()) & SERVICE_STAT) + return service(drive); + + /* + * we have pending commands, wait for interrupt + */ + set_irq(drive, ide_dmaq_intr); + + return ide_started; +} + +ide_startstop_t ide_dmaq_complete(struct ata_device *drive, struct request *rq, u8 stat) +{ + u8 dma_stat; + + /* + * transfer was in progress, stop DMA engine + */ + dma_stat = udma_stop(drive); + + /* + * must be end of I/O, check status and complete as necessary + */ + if (unlikely(!OK_STAT(stat, READY_STAT, drive->bad_wstat | DRQ_STAT))) { + printk(KERN_ERR "%s: %s: error status %x\n", __FUNCTION__, drive->name,stat); + ide_dump_status(drive, __FUNCTION__, stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + if (dma_stat) + printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); + + TCQ_PRINTK("%s: ending %p, tag %d\n", __FUNCTION__, rq, rq->tag); + __ide_end_request(drive, rq, !dma_stat, rq->nr_sectors); + + /* + * we completed this command, check if we can service a new command + */ + return check_service(drive); +} + +/* + * intr handler for queued dma operations. this can be entered for two + * reasons: + * + * 1) device has completed dma transfer + * 2) service request to start a command + * + * if the drive has an active tag, we first complete that request before + * processing any pending SERVICE. + */ +static ide_startstop_t ide_dmaq_intr(struct ata_device *drive, struct request *rq) +{ + u8 stat = GET_STAT(); + + TCQ_PRINTK("%s: stat=%x\n", __FUNCTION__, stat); + + /* + * if a command completion interrupt is pending, do that first and + * check service afterwards + */ + if (rq) + return ide_dmaq_complete(drive, rq, stat); + + /* + * service interrupt + */ + if (stat & SERVICE_STAT) { + TCQ_PRINTK("%s: SERV (stat=%x)\n", __FUNCTION__, stat); + return service(drive); + } + + printk("%s: stat=%x, not expected\n", __FUNCTION__, stat); + return check_service(drive); +} + +/* + * Check if the ata adapter this drive is attached to supports the + * NOP auto-poll for multiple tcq enabled drives on one channel. + */ +static int check_autopoll(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + struct ata_taskfile args; + int drives = 0, i; + + /* + * only need to probe if both drives on a channel support tcq + */ + for (i = 0; i < MAX_DRIVES; i++) + if (drive->channel->drives[i].present &&drive->type == ATA_DISK) + drives++; + + if (drives <= 1) + return 0; + + memset(&args, 0, sizeof(args)); + + args.taskfile.feature = 0x01; + args.taskfile.command = WIN_NOP; + ide_cmd_type_parser(&args); + + /* + * do taskfile and check ABRT bit -- intelligent adapters will not + * pass NOP with sub-code 0x01 to device, so the command will not + * fail there + */ + ide_raw_taskfile(drive, &args, NULL); + if (args.taskfile.feature & ABRT_ERR) + return 1; + + ch->auto_poll = 1; + printk("%s: NOP Auto-poll enabled\n", ch->name); + return 0; +} + +/* + * configure the drive for tcq + */ +static int configure_tcq(struct ata_device *drive) +{ + int tcq_mask = 1 << 1 | 1 << 14; + int tcq_bits = tcq_mask | 1 << 15; + struct ata_taskfile args; + + /* + * bit 14 and 1 must be set in word 83 of the device id to indicate + * support for dma queued protocol, and bit 15 must be cleared + */ + if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask) + return -EIO; + + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_EN_WCACHE; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: failed to enable write cache\n", drive->name); + return 1; + } + + /* + * disable RELease interrupt, it's quicker to poll this after + * having sent the command opcode + */ + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_DIS_RI; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: disabling release interrupt fail\n", drive->name); + return 1; + } + +#ifdef IDE_TCQ_FIDDLE_SI + /* + * enable SERVICE interrupt + */ + memset(&args, 0, sizeof(args)); + args.taskfile.feature = SETFEATURES_EN_SI; + args.taskfile.command = WIN_SETFEATURES; + ide_cmd_type_parser(&args); + + if (ide_raw_taskfile(drive, &args, NULL)) { + printk("%s: enabling service interrupt fail\n", drive->name); + return 1; + } +#endif + + return 0; +} + +static int tcq_wait_dataphase(struct ata_device *drive) +{ + u8 stat; + int i; + + while ((stat = GET_STAT()) & BUSY_STAT) + udelay(10); + + if (OK_STAT(stat, READY_STAT | DRQ_STAT, drive->bad_wstat)) + return 0; + + i = 0; + udelay(1); + while (!OK_STAT(GET_STAT(), READY_STAT | DRQ_STAT, drive->bad_wstat)) { + if (unlikely(i++ > IDE_TCQ_WAIT)) + return 1; + + udelay(10); + } + + return 0; +} + +/**************************************************************************** + * UDMA transfer handling functions. + */ + +/* + * Invoked from a SERVICE interrupt, command etc already known. Just need to + * start the dma engine for this tag. + */ +static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + + TCQ_PRINTK("%s: setting up queued %d\n", __FUNCTION__, rq->tag); + if (!test_bit(IDE_BUSY, &ch->hwgroup->flags)) + printk("queued_rw: IDE_BUSY not set\n"); + + if (tcq_wait_dataphase(drive)) + return ide_stopped; + + if (ata_start_dma(drive, rq)) + return ide_stopped; + + set_irq(drive, ide_dmaq_intr); + if (!udma_start(drive, rq)) + return ide_started; + + return ide_stopped; +} + +/* + * Start a queued command from scratch. + */ +ide_startstop_t udma_tcq_taskfile(struct ata_device *drive, struct request *rq) +{ + u8 stat; + u8 feat; + + struct ata_taskfile *args = rq->special; + + TCQ_PRINTK("%s: start tag %d\n", drive->name, rq->tag); + + /* + * set nIEN, tag start operation will enable again when + * it is safe + */ + drive_ctl_nien(drive, 1); + + OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG); + + if (wait_altstat(drive, &stat, BUSY_STAT)) { + ide_dump_status(drive, "queued start", stat); + tcq_invalidate_queue(drive); + return ide_stopped; + } + + drive_ctl_nien(drive, 0); + + if (stat & ERR_STAT) { + ide_dump_status(drive, "tcq_start", stat); + return ide_stopped; + } + + /* + * drive released the bus, clear active tag and + * check for service + */ + if ((feat = GET_FEAT()) & NSEC_REL) { + drive->immed_rel++; + HWGROUP(drive)->rq = NULL; + set_irq(drive, ide_dmaq_intr); + + TCQ_PRINTK("REL in queued_start\n"); + + if ((stat = GET_STAT()) & SERVICE_STAT) + return service(drive); + + return ide_released; + } + + TCQ_PRINTK("IMMED in queued_start\n"); + drive->immed_comp++; + + return udma_tcq_start(drive, rq); +} + +/* + * For now assume that command list is always as big as we need and don't + * attempt to shrink it on tcq disable. + */ +int udma_tcq_enable(struct ata_device *drive, int on) +{ + int depth = drive->using_tcq ? drive->queue_depth : 0; + + /* + * disable or adjust queue depth + */ + if (!on) { + if (drive->using_tcq) + printk("%s: TCQ disabled\n", drive->name); + drive->using_tcq = 0; + return 0; + } + + if (configure_tcq(drive)) { + drive->using_tcq = 0; + return 1; + } + + /* + * enable block tagging + */ + if (!blk_queue_tagged(&drive->queue)) + blk_queue_init_tags(&drive->queue, IDE_MAX_TAG); + + /* + * check auto-poll support + */ + check_autopoll(drive); + + if (depth != drive->queue_depth) + printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth); + + drive->using_tcq = 1; + return 0; +} diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c --- a/drivers/ide/trm290.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/trm290.c Sun May 5 20:39:49 2002 @@ -173,43 +173,76 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA -static int trm290_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int trm290_udma_start(struct ata_device *drive, struct request *__rq) { - struct ata_channel *hwif = drive->channel; - unsigned int count, reading = 2, writing = 0; + /* Nothing to be done here. */ + return 0; +} + +static int trm290_udma_stop(struct ata_device *drive) +{ + struct ata_channel *ch = drive->channel; + + drive->waiting_for_dma = 0; + udma_destroy_table(ch); /* purge DMA mappings */ + return (inw(ch->dma_base + 2) != 0x00ff); +} + +static int do_udma(unsigned int reading, struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + unsigned int count, writing; - switch (func) { - case ide_dma_write: - reading = 0; - writing = 1; + if (!reading) { + reading = 0; + writing = 1; #ifdef TRM290_NO_DMA_WRITES - break; /* always use PIO for writes */ + trm290_prepare_drive(drive, 0); /* select PIO xfer */ + + return 1; #endif - case ide_dma_read: - if (!(count = ide_build_dmatable(drive, func))) - break; /* try PIO instead of DMA */ - trm290_prepare_drive(drive, 1); /* select DMA xfer */ - outl(hwif->dmatable_dma|reading|writing, hwif->dma_base); - drive->waiting_for_dma = 1; - outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ - if (drive->type != ATA_DISK) - return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - return 0; - case ide_dma_begin: - return 0; - case ide_dma_end: - drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (inw(hwif->dma_base+2) != 0x00ff); - case ide_dma_test_irq: - return (inw(hwif->dma_base+2) == 0x00ff); - default: - return ide_dmaproc(func, drive, rq); + } else { + reading = 2; + writing = 0; + } + + if (!(count = udma_new_table(ch, rq))) { + trm290_prepare_drive(drive, 0); /* select PIO xfer */ + return 1; /* try PIO instead of DMA */ } - trm290_prepare_drive(drive, 0); /* select PIO xfer */ - return 1; + + trm290_prepare_drive(drive, 1); /* select DMA xfer */ + outl(ch->dmatable_dma|reading|writing, ch->dma_base); + drive->waiting_for_dma = 1; + outw((count * 2) - 1, ch->dma_base+2); /* start DMA */ + + if (drive->type != ATA_DISK) + return 0; + + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + + return 0; +} + +static int trm290_udma_read(struct ata_device *drive, struct request *rq) +{ + return do_udma(1, drive, rq); +} + +static int trm290_udma_write(struct ata_device *drive, struct request *rq) +{ + return do_udma(0, drive, rq); +} + +static int trm290_udma_irq_status(struct ata_device *drive) +{ + return (inw(drive->channel->dma_base + 2) == 0x00ff); +} + +static int trm290_dmaproc(struct ata_device *drive) +{ + return XXX_ide_dmaproc(drive); } #endif @@ -263,7 +296,12 @@ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3); #ifdef CONFIG_BLK_DEV_IDEDMA - hwif->udma = trm290_dmaproc; + hwif->udma_start = trm290_udma_start; + hwif->udma_stop = trm290_udma_stop; + hwif->udma_read = trm290_udma_read; + hwif->udma_write = trm290_udma_write; + hwif->udma_irq_status = trm290_udma_irq_status; + hwif->XXX_udma = trm290_dmaproc; #endif hwif->selectproc = &trm290_selectproc; diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c --- a/drivers/ide/via82cxxx.c Sun May 5 20:39:49 2002 +++ b/drivers/ide/via82cxxx.c Sun May 5 20:39:49 2002 @@ -356,37 +356,24 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA - -/* - * via82cxxx_dmaproc() is a callback from upper layers that can do - * a lot, but we use it for DMA/PIO tuning only, delegating everything - * else to the default ide_dmaproc(). - */ - -int via82cxxx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) +static int via82cxxx_dmaproc(struct ata_device *drive) { + short w80 = drive->channel->udma_four; - if (func == ide_dma_check) { - - short w80 = drive->channel->udma_four; - - short speed = ata_timing_mode(drive, + short speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) | (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) | (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) | (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0)); - via_set_drive(drive, speed); + via_set_drive(drive, speed); - func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO) - ? ide_dma_on : ide_dma_off_quietly; - } + udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0); - return ide_dmaproc(func, drive, rq); + return 0; } - -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* * The initialization callback. Here we determine the IDE chip type @@ -546,13 +533,13 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->highmem = 1; - hwif->udma = &via82cxxx_dmaproc; -#ifdef CONFIG_IDEDMA_AUTO + hwif->XXX_udma = &via82cxxx_dmaproc; +# ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; -#endif +# endif } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif } /* diff -Nru a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in --- a/drivers/net/appletalk/Config.in Sun May 5 20:39:49 2002 +++ b/drivers/net/appletalk/Config.in Sun May 5 20:39:49 2002 @@ -9,13 +9,13 @@ tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC tristate ' COPS LocalTalk PC support' CONFIG_COPS if [ "$CONFIG_COPS" != "n" ]; then - bool ' Dayna firmware support' CONFIG_COPS_DAYNA $CONFIG_COPS - bool ' Tangent firmware support' CONFIG_COPS_TANGENT $CONFIG_COPS + bool ' Dayna firmware support' CONFIG_COPS_DAYNA + bool ' Tangent firmware support' CONFIG_COPS_TANGENT fi dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK if [ "$CONFIG_IPDDP" != "n" ]; then - bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP $CONFIG_IPDDP - bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP $CONFIG_IPDDP + bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP + bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi fi endmenu diff -Nru a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in --- a/drivers/net/wan/Config.in Sun May 5 20:39:49 2002 +++ b/drivers/net/wan/Config.in Sun May 5 20:39:49 2002 @@ -69,13 +69,14 @@ dep_tristate ' Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)' CONFIG_PC300 $CONFIG_HDLC $CONFIG_PCI if [ "$CONFIG_PC300" != "n" ]; then - if [ "$CONFIG_PPP" != "n" -a "$CONFIG_PPP_MULTLINK" != "n" -a "$CONFIG_PPP_SYNCTTY" != "n" -a "$CONFIG_HDLC_PPP" = "y" ]; then - bool ' Cyclades-PC300 MLPPP support' CONFIG_PC300_MLPPP - else - comment ' Cyclades-PC300 MLPPP support is disabled.'+ comment ' Refer to the file README.mlppp, provided by PC300 package.' - fi + if [ "$CONFIG_PPP" != "n" -a "$CONFIG_PPP_MULTLINK" != "n" -a \ + "$CONFIG_PPP_SYNCTTY" != "n" -a "$CONFIG_HDLC_PPP" = "y" ]; then + bool ' Cyclades-PC300 MLPPP support' CONFIG_PC300_MLPPP + else + comment 'Cyclades-PC300 MLPPP support is disabled.' + comment 'Refer to the file README.mlppp, provided by PC300 package.' + fi fi - dep_tristate ' SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC dep_tristate ' Moxa C101 support' CONFIG_C101 $CONFIG_HDLC diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Sun May 5 20:39:49 2002 +++ b/drivers/pci/pci.ids Sun May 5 20:39:49 2002 @@ -5087,22 +5087,35 @@ 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB AC'97 Modem 2428 82801AB PCI Bridge - 2440 82820 820 (Camino 2) Chipset ISA Bridge (ICH2) - 2442 82820 820 (Camino 2) Chipset USB (Hub A) - 2443 82820 820 (Camino 2) Chipset SMBus - 2444 82820 820 (Camino 2) Chipset USB (Hub B) - 2445 82820 820 (Camino 2) Chipset AC'97 Audio Controller - 2446 82820 820 (Camino 2) Chipset AC'97 Modem Controller - 2448 82820 820 (Camino 2) Chipset PCI (-M) - 2449 82820 (ICH2) Chipset Ethernet Controller - 244a 82820 820 (Camino 2) Chipset IDE U100 (-M) - 244b 82820 820 (Camino 2) Chipset IDE U100 - 244c 82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M) - 244e 82820 820 (Camino 2) Chipset PCI - 245b 82801E C-ICH IDE - 2485 AC'97 Audio Controller - 248a 82801CAM ICH3-M IDE - 248b 82801CA ICH3 IDE + 2440 82801BA ISA Bridge (LPC) + 2442 82801BA/BAM USB (Hub #1) + 2443 82801BA/BAM SMBus + 2444 82801BA/BAM USB (Hub #2) + 2445 82801BA/BAM AC'97 Audio + 2446 82801BA/BAM AC'97 Modem + 2448 82801BAM/CAM PCI Bridge + 2449 82801BA/BAM/CA/CAM Ethernet Controller + 244a 82801BAM IDE U100 + 244b 82801BA IDE U100 + 244c 82801BAM ISA Bridge (LPC) + 244e 82801BA/CA PCI Bridge + 2450 82801E ISA Bridge (LPC) + 2452 82801E USB + 2453 82801E SMBus + 2459 82801E Ethernet Controller 0 + 245b 82801E IDE U100 + 245d 82801E Ethernet Controller 1 + 245e 82801E PCI Bridge + 2480 82801CA ISA Bridge (LPC) + 2482 82801CA/CAM USB (Hub #1) + 2483 82801CA/CAM SMBus + 2484 82801CA/CAM USB (Hub #2) + 2485 82801CA/CAM AC'97 Audio + 2486 82801CA/CAM AC'97 Modem + 2487 82801CA/CAM USB (Hub #3) + 248a 82801CAM IDE U100 + 248b 82801CA IDE U100 + 248c 82801CAM ISA Bridge (LPC) 24cb 82801DB ICH4 IDE 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Sun May 5 20:39:49 2002 +++ b/drivers/scsi/ide-scsi.c Sun May 5 20:39:49 2002 @@ -328,7 +328,7 @@ printk ("ide-scsi: %s: DMA complete\n", drive->name); #endif /* IDESCSI_DEBUG_LOG */ pc->actually_transferred=pc->request_transfer; - (void) drive->channel->udma(ide_dma_end, drive, NULL); + udma_stop(drive); } status = GET_STAT(); /* Clear the interrupt */ @@ -429,8 +429,12 @@ pc->current_position=pc->buffer; bcount = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ - if (drive->using_dma && rq->bio) - dma_ok = !drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq); + if (drive->using_dma && rq->bio) { + if (test_bit (PC_WRITING, &pc->flags)) + dma_ok = !udma_write(drive, rq); + else + dma_ok = !udma_read(drive, rq); + } SELECT_DRIVE(drive->channel, drive); if (IDE_CONTROL_REG) @@ -441,7 +445,7 @@ if (dma_ok) { set_bit(PC_DMA_IN_PROGRESS, &pc->flags); - (void) drive->channel->udma(ide_dma_begin, drive, NULL); + udma_start(drive, rq); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { ide_set_handler(drive, idescsi_transfer_pc, get_timeout(pc), NULL); diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c Sun May 5 20:39:50 2002 +++ b/drivers/scsi/scsi_debug.c Sun May 5 20:39:50 2002 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,7 @@ #include "scsi.h" #include "hosts.h" -#include +#include #ifndef LINUX_VERSION_CODE #include diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sun May 5 20:39:49 2002 +++ b/drivers/scsi/sd.c Sun May 5 20:39:49 2002 @@ -41,7 +41,7 @@ #include #include #include - +#include #include #include diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile Sun May 5 20:39:49 2002 +++ b/drivers/video/Makefile Sun May 5 20:39:49 2002 @@ -1,5 +1,5 @@ # Makefile for the Linux video drivers. -# 5 Aug 1999, James Simmons, +# 5 Aug 1999, James Simmons, # Rewritten to use lists instead of if-statements. O_TARGET := video.o @@ -10,7 +10,7 @@ # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \ - fbcon-afb.o fbcon-ilbm.o fbgen.o \ + fbcon-afb.o fbcon-ilbm.o fbcon-accel.o \ fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ diff -Nru a/drivers/video/atafb.c b/drivers/video/atafb.c --- a/drivers/video/atafb.c Sun May 5 20:39:49 2002 +++ b/drivers/video/atafb.c Sun May 5 20:39:49 2002 @@ -1596,7 +1596,7 @@ var->xoffset = up(var->xoffset, 2); } par->hw.falcon.line_offset = bpp * - (fb_display[fb_info.currcon].var.xres_virtual - fb_display[currcon].var.xres) / 16; + (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; if (par->hw.falcon.xoffset) par->hw.falcon.line_offset -= bpp; xoffset = var->xoffset - par->hw.falcon.xoffset; @@ -2840,8 +2840,8 @@ if (!options || !*options) return 0; - - for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + + while ((this_opt = strsep(options, ",")) != NULL) { if (!*this_opt) continue; if ((temp=get_video_mode(this_opt))) default_par=temp; diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c --- a/drivers/video/aty/atyfb_base.c Sun May 5 20:39:49 2002 +++ b/drivers/video/aty/atyfb_base.c Sun May 5 20:39:49 2002 @@ -87,6 +87,9 @@ #include #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif #ifdef CONFIG_NVRAM #include #endif @@ -815,6 +818,13 @@ display_info.disp_reg_address = info->ati_regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->frame_buffer_phys, + (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, + ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } static int atyfb_decode_var(const struct fb_var_screeninfo *var, diff -Nru a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c --- a/drivers/video/aty128fb.c Sun May 5 20:39:50 2002 +++ b/drivers/video/aty128fb.c Sun May 5 20:39:50 2002 @@ -70,6 +70,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif /* CONFIG_BOOTX_TEXT */ #include