This list is closed, nobody may subscribe to it.
2004 |
Jan
(53) |
Feb
(78) |
Mar
(34) |
Apr
(26) |
May
(25) |
Jun
(34) |
Jul
(16) |
Aug
(16) |
Sep
(2) |
Oct
(58) |
Nov
(13) |
Dec
(32) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(62) |
Feb
(4) |
Mar
(40) |
Apr
(9) |
May
(13) |
Jun
(26) |
Jul
(32) |
Aug
(24) |
Sep
(18) |
Oct
(18) |
Nov
(14) |
Dec
|
2006 |
Jan
(15) |
Feb
(2) |
Mar
(23) |
Apr
(2) |
May
(2) |
Jun
(13) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2007 |
Jan
(1) |
Feb
(45) |
Mar
|
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(31) |
Dec
(5) |
2008 |
Jan
(6) |
Feb
(34) |
Mar
(113) |
Apr
(40) |
May
(19) |
Jun
(5) |
Jul
(41) |
Aug
(13) |
Sep
(53) |
Oct
(4) |
Nov
(53) |
Dec
|
2009 |
Jan
(1) |
Feb
(29) |
Mar
(66) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(163) |
Nov
|
Dec
(91) |
From: <he...@us...> - 2005-03-22 19:13:50
|
Update of /cvsroot/gc-linux/htdocs/xml/en In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27684 Modified Files: news.xml Log Message: 22 March 2005, psolore Index: news.xml =================================================================== RCS file: /cvsroot/gc-linux/htdocs/xml/en/news.xml,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- news.xml 15 Mar 2005 00:14:31 -0000 1.33 +++ news.xml 22 Mar 2005 19:13:11 -0000 1.34 @@ -2,6 +2,11 @@ <?xml-stylesheet href="news.xsl" type="text/xsl"?> <news> <item> + <date>22 March 2005</date> + <title>psolore</title> + <text>The psoload reloader, aka psolore, is a simple command line tool to reload code on a GameCube previously booted with PSOload or SDload, just like psoload -r does. It works on Linux and comes with source code. Look at the <a href="down/isobel/psolore/readme.txt">readme</a> for more information, or download the <a href="down/isobel/psolore/psolore.tgz">tarball</a>.</text> + </item> + <item> <date>15 March 2005</date> <title>New improved EXI framework</title> <text>A new kernel Expansion Interface subsystem is available on CVS. It is a code rewrite based on apgo's original driver model framework and some of Scream|CT's recent contributions. The good news is that the RTC and BBA drivers are using now the new framework and cpu usage is much lower. The not so good news is that we've dropped temporarily the memcard and SD drivers while they get reworked. The new stuff is already included in the <a href="docs/download.html">Latest Kernel Build</a>, updated to 2.6.11.</text> |
From: <he...@us...> - 2005-03-20 22:35:27
|
Update of /cvsroot/gc-linux/linux/drivers/block In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15978/drivers/block Modified Files: gcn-aram.c Log Message: New ARAM rewrite. The driver uses now the driver model and the kernel DMA API. Index: gcn-aram.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/block/gcn-aram.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- gcn-aram.c 24 Feb 2005 21:36:42 -0000 1.5 +++ gcn-aram.c 20 Mar 2005 22:35:14 -0000 1.6 @@ -1,12 +1,12 @@ /* * drivers/block/gcn-aram.c * - * Nintendo GameCube ARAM block device - * Copyright (C) 2004 The GameCube Linux Team + * Nintendo GameCube Auxiliary RAM block driver + * Copyright (C) 2004-2005 The GameCube Linux Team + * Copyright (C) 2005 Todd Jeffreys <to...@vo...> + * Copyright (C) 2005 Albert Herranz * - * Based on previous work by Franz Lehner, apparently inspired on: - * z2ram.c - * Copyright (C) 1994 by Ingo Wilken (Ing...@in...) + * Based on previous work by Franz Lehner. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,231 +15,335 @@ * */ -#define DEVICE_NAME "ARAM" - -#include <linux/major.h> -#include <linux/vmalloc.h> -#include <linux/init.h> #include <linux/module.h> +#include <linux/major.h> #include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <asm/setup.h> -#include <asm/bitops.h> -#include <asm/pgtable.h> -#include <asm/cacheflush.h> -#include <linux/interrupt.h> - #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/hdreg.h> /* HDIO_GETGEO */ - +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> #include <asm/io.h> -#include <asm/scatterlist.h> -#define ARAM_MAJOR Z2RAM_MAJOR -#define HARD_SECTOR_SIZE 512 +#define DRV_MODULE_NAME "gcn-aram" +#define DRV_DESCRIPTION "Nintendo GameCube Auxiliary RAM block driver" +#define DRV_AUTHOR "Todd Jeffreys <to...@vo...>, " \ + "Albert Herranz" -//#define ARAM_DEBUG -//#define ARAM_DBG printk -#define ARAM_DBG(format, arg...); { } +static char aram_driver_version[] = "2.0"; -#define ARAM_SOUNDMEMORYOFFSET 0 -#define ARAM_BUFFERSIZE (16*1024*1024 - ARAM_SOUNDMEMORYOFFSET) +#define aram_printk(level, format, arg...) \ + printk(level DRV_MODULE_NAME ": " format , ## arg) -#define AI_DSP_CSR (void __iomem *)0xCC00500A -#define AI_CSR_RES (1<<0) -#define AI_CSR_PIINT (1<<1) -#define AI_CSR_HALT (1<<2) -#define AI_CSR_AIDINT (1<<3) -#define AI_CSR_AIDINTMASK (1<<4) -#define AI_CSR_ARINT (1<<5) -#define AI_CSR_ARINTMASK (1<<6) -#define AI_CSR_DSPINT (1<<7) -#define AI_CSR_DSPINTMASK (1<<8) -#define AI_CSR_DSPDMA (1<<9) -#define AI_CSR_RESETXXX (1<<11) +#ifdef ARAM_DEBUG +# define DBG(fmt, args...) \ + printk(KERN_ERR "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DBG(fmt, args...) +#endif -#define AR_SIZE (void __iomem*)0xCC005012 -#define AR_MODE (void __iomem*)0xCC005016 -#define AR_MODE_ACCELERATOR (1 << 0) +/* + * Hardware. + */ +#define ARAM_IRQ 6 -#define AR_REFRESH (void __iomem*)0xCC00501A +#define ARAM_DMA_ALIGN 0x1f /* 32 bytes */ -#define AR_DMA_MMADDR (void __iomem*)0xCC005020 -#define AR_DMA_ARADDR (void __iomem*)0xCC005024 -#define AR_DMA_CNT_H (void __iomem*)0xCC005028 -#define AR_DMA_CNT_L (void __iomem*)0xCC00502A -#define AR_DMA_CNT AR_DMA_CNT_H +#define DSP_BASE 0xcc005000 +#define DSP_SIZE 0x200 -#define ARAM_READ (1 << 31) -#define ARAM_WRITE 0 +#define DSP_IO_BASE ((void __iomem *)DSP_BASE) -#define ARAM_DMA_ALIGNMENT_MASK 0x1F +#define DSP_CSR 0x00a +#define DSP_CSR_RES (1<<0) +#define DSP_CSR_PIINT (1<<1) +#define DSP_CSR_HALT (1<<2) +#define DSP_CSR_AIDINT (1<<3) +#define DSP_CSR_AIDINTMASK (1<<4) +#define DSP_CSR_ARINT (1<<5) +#define DSP_CSR_ARINTMASK (1<<6) +#define DSP_CSR_DSPINT (1<<7) +#define DSP_CSR_DSPINTMASK (1<<8) +#define DSP_CSR_DSPDMA (1<<9) +#define DSP_CSR_RESETXXX (1<<11) -#define ARAM_IRQ 6 -#define IRQ_PARAM (void*)0xFFFFFFFA +#define AR_SIZE 0x012 -static spinlock_t aram_lock = SPIN_LOCK_UNLOCKED; -static struct block_device_operations aram_fops; -static struct gendisk *aram_gendisk; -static struct request_queue *aram_queue; -static struct request * volatile irq_request; -static u32 refCount; +#define AR_MODE 0x016 +#define AR_MODE_ACCELERATOR (1 << 0) -static inline void ARAM_StartDMA(void *mmAddr, unsigned long arAddr, - unsigned long length, unsigned long type) +#define AR_REFRESH 0x01a + +#define AR_DMA_MMADDR 0x020 + +#define AR_DMA_ARADDR 0x024 + +#define AR_DMA_CNT_H 0x028 +#define AR_READ (1 << 31) +#define AR_WRITE 0 + +#define AR_DMA_CNT_L 0x02a + +#define AR_DMA_CNT AR_DMA_CNT_H + +/* + * Driver settings + */ +#define ARAM_NAME "aram" +#define ARAM_MAJOR Z2RAM_MAJOR + +#define ARAM_SECTOR_SIZE PAGE_SIZE + +#define ARAM_SOUNDMEMORYOFFSET 0 +#define ARAM_BUFFERSIZE (16*1024*1024 - ARAM_SOUNDMEMORYOFFSET) + + + +struct aram_device { + spinlock_t lock; + + int irq; + void __iomem *io_base; + spinlock_t io_lock; + + struct block_device_operations fops; + struct gendisk *disk; + struct request_queue *queue; + + struct request *req; + dma_addr_t dma_addr; + size_t dma_len; + + int ref_count; + + struct platform_device pdev; /* must be last member */ +}; + + +/* get the aram device given the platform device of an aram device */ +#define to_aram_device(n) container_of(n,struct aram_device,pdev) + +/* + * Converts a request direction into a DMA data direction. + */ +static inline enum dma_data_direction rq_dir_to_dma_dir(struct request *req) { -#ifdef ARAM_DEBUG - if ((readw(AI_DSP_CSR) & AI_CSR_DSPDMA) || - (readl(AR_DMA_CNT) & 0x7FFFFFFF)) { - printk("StartDMA called, but there is already an outstanding DMA request!\n"); + if (rq_data_dir(req) == READ) { + return DMA_FROM_DEVICE; + } else { + return DMA_TO_DEVICE; } - else if (((u32)mmAddr & 0x1F) || (length & 0x1F)) { - printk("StartDMA called on unaligned data\n"); +} + +/* + * Converts a request direction into an ARAM data direction. + */ +static inline int rq_dir_to_aram_dir(struct request *req) +{ + if (rq_data_dir(req) == READ) { + return AR_READ; + } else { + return AR_WRITE; } -#endif - /* process */ - writel(virt_to_phys(mmAddr),AR_DMA_MMADDR); - writel(arAddr,AR_DMA_ARADDR); +} + + +/* + * Starts an ARAM DMA transfer. + */ +static void aram_start_dma_transfer(struct aram_device *adev, + unsigned long aram_addr) +{ + void __iomem *io_base = adev->io_base; + dma_addr_t dma_addr = adev->dma_addr; + size_t dma_len = adev->dma_len; + + /* DMA transfers require proper alignment */ + BUG_ON((dma_addr & ARAM_DMA_ALIGN) != 0 || + (dma_len & ARAM_DMA_ALIGN) != 0); + + writel(dma_addr, io_base + AR_DMA_MMADDR); + writel(aram_addr, io_base + AR_DMA_ARADDR); + /* writing the low-word kicks off the DMA */ - writel(type | length,AR_DMA_CNT); + writel(rq_dir_to_aram_dir(adev->req) | dma_len, io_base + AR_DMA_CNT); } -static irqreturn_t aram_irq(int irq,void *dev_id,struct pt_regs *regs) +/* + * Handles ARAM interrupts. + */ +static irqreturn_t aram_irq_handler(int irq, void *dev0, struct pt_regs *regs) { - unsigned long flags; - u16 tmp; + struct aram_device *adev = dev0; struct request *req; + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; + u16 csr; + unsigned long flags; - if (readw(AI_DSP_CSR) & AI_CSR_ARINT) { -#ifdef ARAM_DEBUG - if (readw(AI_DSP_CSR) & AI_CSR_DSPDMA) { - flags = readl(AR_DMA_CNT); - do { - cpu_relax(); - } while(readw(AI_DSP_CSR) & AI_CSR_DSPDMA); - printk("Received interrupt before completion, number of bytes remaining was %lu\n",flags); - } - else if ((flags = (readl(AR_DMA_CNT) & 0x7FFFFFFF))) { - printk("Received interrupt before completion, number of bytes remaining was %lu\n",flags); - } -#endif - /* ack the int, but only ours */ - local_irq_save(flags); - tmp = readw(AI_DSP_CSR); - tmp &= ~(AI_CSR_AIDINT | AI_CSR_DSPINT); - writew(tmp,AI_DSP_CSR); - local_irq_restore(flags); + spin_lock_irqsave(&adev->io_lock, flags); + + csr = readw(csr_reg); + + /* + * Do nothing if the interrupt is not targetted for us. + * (We share this interrupt with the sound driver). + */ + if (!(csr & DSP_CSR_ARINT)) { + spin_unlock_irqrestore(&adev->io_lock, flags); + return IRQ_NONE; + } + + /* strictly ack the ARAM interrupt, and nothing more */ + csr &= ~(DSP_CSR_AIDINT | DSP_CSR_DSPINT); + writew(csr, csr_reg); + + /* pick up current request being serviced */ + req = adev->req; + adev->req = NULL; + + spin_unlock_irqrestore(&adev->io_lock, flags); - /* now process */ - spin_lock(&aram_lock); - if ((req = irq_request)) { - /* complete request */ - if (!end_that_request_first(req,1, - req->current_nr_sectors)) { - add_disk_randomness(req->rq_disk); - end_that_request_last(req); - } - else { - printk(KERN_ERR DEVICE_NAME " device still thinks there are requests but DMA has finished\n"); - } - irq_request = NULL; - /* start queue back up */ - blk_start_queue(aram_queue); - } - else { - printk(KERN_ERR DEVICE_NAME " received an interrupt but no irq_request set\n"); + if (req) { + if (!end_that_request_first(req, 1, req->current_nr_sectors)) { + add_disk_randomness(req->rq_disk); + end_that_request_last(req); } - spin_unlock(&aram_lock); - /* return handled */ - return IRQ_HANDLED; + dma_unmap_single(&adev->pdev.dev, adev->dma_addr, adev->dma_len, + rq_dir_to_dma_dir(req)); + spin_lock(&adev->lock); + blk_start_queue(adev->queue); + spin_unlock(&adev->lock); + } else { + aram_printk(KERN_ERR, "ignoring interrupt, no request\n"); } - return IRQ_NONE; -} + return IRQ_HANDLED; +} -static void do_aram_request(request_queue_t * q) +/* + * Performs block layer requests. + */ +static void aram_do_request(request_queue_t *q) { + struct aram_device *adev = q->queuedata; struct request *req; - unsigned long start; - unsigned long len; + unsigned long aram_addr; + size_t len; unsigned long flags; - - while ((req = elv_next_request(q))) { - /* get length */ - start = req->sector << 9; - len = req->current_nr_sectors << 9; - - if ((start + len) > ARAM_BUFFERSIZE) { - printk(KERN_ERR DEVICE_NAME - ": bad access: block=%lu, count=%lu\n", - (unsigned long)req->sector,len); - end_request(req, 0); - continue; - } - else if (irq_request) { /* already scheduled? */ + + req = elv_next_request(q); + while(req) { + spin_lock_irqsave(&adev->io_lock, flags); + + /* we can schedule just a single request each time */ + if (adev->req) { + spin_unlock_irqrestore(&adev->io_lock, flags); blk_stop_queue(q); - goto exit_func; + break; } - /* dequeue */ + blkdev_dequeue_request(req); + + /* ignore requests that we can't handle */ + if (!blk_fs_request(req)) { + spin_unlock_irqrestore(&adev->io_lock, flags); + continue; + } + + /* store the request being handled */ + adev->req = req; blk_stop_queue(q); - irq_request = req; - /* schedule DMA */ - if (rq_data_dir(req) == READ) { - invalidate_dcache_range((unsigned long)req->buffer, - (unsigned long)req->buffer + - len); - ARAM_StartDMA(req->buffer, - start + ARAM_SOUNDMEMORYOFFSET, len, - ARAM_READ); - } - else { - clean_dcache_range((unsigned long)req->buffer, - (unsigned long)req->buffer + len); - ARAM_StartDMA(req->buffer, - start + ARAM_SOUNDMEMORYOFFSET, len, - ARAM_WRITE); + + spin_unlock_irqrestore(&adev->io_lock, flags); + + /* calculate the ARAM address and length */ + aram_addr = req->sector << 9; + len = req->current_nr_sectors << 9; + + /* give up if the request goes out of bounds */ + if (aram_addr + len > ARAM_BUFFERSIZE) { + aram_printk(KERN_ERR, "bad access: block=%lu," + " size=%u\n", (unsigned long)req->sector, + len); + /* XXX correct? the request is already dequeued */ + end_request(req, 0); + continue; } - goto exit_func; + + BUG_ON(req->nr_phys_segments != 1); + + /* perform DMA mappings */ + adev->dma_len = len; + adev->dma_addr = dma_map_single(&adev->pdev.dev, req->buffer, + len, rq_dir_to_dma_dir(req)); + + /* start the DMA transfer */ + aram_start_dma_transfer(adev, + ARAM_SOUNDMEMORYOFFSET + aram_addr); + break; } - exit_func: } +/* + * Opens the ARAM device. + */ static int aram_open(struct inode *inode, struct file *filp) { + struct aram_device *adev = inode->i_bdev->bd_disk->private_data; unsigned long flags; - - ARAM_DBG("A-RAM Open device\n"); + int retval = 0; + + spin_lock_irqsave(&adev->lock, flags); + /* only allow a minor of 0 to be opened */ - if (iminor(inode)) - return -ENODEV; - /* allow multiple people to open this file */ - spin_lock_irqsave(&aram_lock,flags); - ++refCount; - spin_unlock_irqrestore(&aram_lock,flags); - return 0; + if (iminor(inode)) { + retval = -ENODEV; + goto out; + } + + /* honor exclusive open mode */ + if (adev->ref_count == -1 || + (adev->ref_count && (filp->f_flags & O_EXCL))) { + retval = -EBUSY; + goto out; + } + + if ((filp->f_flags & O_EXCL)) + adev->ref_count = -1; + else + adev->ref_count++; + +out: + spin_unlock_irqrestore(&adev->lock, flags); + return retval; } +/* + * Closes the ARAM device. + */ static int aram_release(struct inode *inode, struct file *filp) { + struct aram_device *adev = inode->i_bdev->bd_disk->private_data; unsigned long flags; - ARAM_DBG("A-RAM Close device\n"); - /* lower ref count */ - spin_lock_irqsave(&aram_lock,flags); - --refCount; - spin_unlock_irqrestore(&aram_lock,flags); + + spin_lock_irqsave(&adev->lock, flags); + if (adev->ref_count > 0) + adev->ref_count--; + else + adev->ref_count = 0; + spin_unlock_irqrestore(&adev->lock, flags); + return 0; } +/* + * Minimal ioctl for the ARAM device. + */ static int aram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct hd_geometry geo; - ARAM_DBG("A-RAM IOCTL\n"); - switch (cmd) { case BLKRAGET: case BLKFRAGET: @@ -265,106 +369,294 @@ } } -static int aram_revalidate(struct gendisk *disk) -{ - set_capacity(disk, ARAM_BUFFERSIZE >> 9); - return 0; -} static struct block_device_operations aram_fops = { .owner = THIS_MODULE, .open = aram_open, .release = aram_release, - .revalidate_disk = aram_revalidate, .ioctl = aram_ioctl, }; +/* + * + */ +static int aram_init_blk_dev(struct aram_device *adev) +{ + struct gendisk *disk; + struct request_queue *queue; + int retval; -int __init aram_init(void) + adev->ref_count = 0; + + retval = register_blkdev(ARAM_MAJOR, ARAM_NAME); + if (retval) + goto err_register_blkdev; + + retval = -ENOMEM; + spin_lock_init(&adev->lock); + spin_lock_init(&adev->io_lock); + queue = blk_init_queue(aram_do_request, &adev->lock); + if (!queue) + goto err_blk_init_queue; + + blk_queue_hardsect_size(queue, ARAM_SECTOR_SIZE); + blk_queue_dma_alignment(queue, ARAM_DMA_ALIGN); + blk_queue_max_phys_segments(queue, 1); + blk_queue_max_hw_segments(queue, 1); + queue->queuedata = adev; + adev->queue = queue; + + disk = alloc_disk(1); + if (!disk) + goto err_alloc_disk; + + disk->major = ARAM_MAJOR; + disk->first_minor = 0; + disk->fops = &aram_fops; + strcpy(disk->disk_name, ARAM_NAME); + strcpy(disk->devfs_name, disk->disk_name); + disk->queue = adev->queue; + set_capacity(disk, ARAM_BUFFERSIZE >> 9); + disk->private_data = adev; + adev->disk = disk; + + add_disk(adev->disk); + + retval = 0; + goto out; + +err_alloc_disk: + blk_cleanup_queue(adev->queue); +err_blk_init_queue: + unregister_blkdev(ARAM_MAJOR, ARAM_NAME); +err_register_blkdev: +out: + return retval; +} + +/* + * + */ +static void aram_exit_blk_dev(struct aram_device *adev) { - int ret; + if (adev->disk) { + del_gendisk(adev->disk); + put_disk(adev->disk); + } + if (adev->queue) + blk_cleanup_queue(adev->queue); + unregister_blkdev(ARAM_MAJOR, ARAM_NAME); +} + +/* + * + */ +static void aram_quiesce(struct aram_device *adev) +{ + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; unsigned long flags; - /* get the irq */ - if ((ret=request_irq(ARAM_IRQ,aram_irq,SA_INTERRUPT | SA_SHIRQ,"ARAM", - IRQ_PARAM))) - goto out_irq; - - if ((ret=register_blkdev(ARAM_MAJOR, DEVICE_NAME))) - goto out_blkdev; - - ret = -ENOMEM; - aram_gendisk = alloc_disk(1); - if (!aram_gendisk) - goto out_disk; - - spin_lock_init(&aram_lock); - - aram_queue = blk_init_queue(do_aram_request, &aram_lock); - if (!aram_queue) - goto out_queue; + /* disable ARAM interrupts */ + spin_lock_irqsave(&adev->io_lock, flags); + writew(readw(csr_reg) & ~DSP_CSR_ARINTMASK, + csr_reg); + spin_unlock_irqrestore(&adev->io_lock, flags); - aram_gendisk->major = ARAM_MAJOR; - aram_gendisk->first_minor = 0; - aram_gendisk->fops = &aram_fops; - strcpy(aram_gendisk->disk_name, "aram"); - strcpy(aram_gendisk->devfs_name, aram_gendisk->disk_name); + /* wait until pending transfers are finished */ + while(readw(csr_reg) & DSP_CSR_DSPDMA) + cpu_relax(); +} - aram_gendisk->queue = aram_queue; +/* + * + */ +static int aram_init_irq(struct aram_device *adev) +{ + u16 __iomem *csr_reg = adev->io_base + DSP_CSR; + unsigned long flags; + int retval; - /* we can only have one segment at a time */ - blk_queue_max_phys_segments(aram_queue,1); - blk_queue_max_hw_segments(aram_queue,1); - /* make sectors equal to the pagesize */ - blk_queue_hardsect_size(aram_queue,HARD_SECTOR_SIZE); - /* set the DMA alignment */ - blk_queue_dma_alignment(aram_queue,ARAM_DMA_ALIGNMENT_MASK); - - set_capacity(aram_gendisk, ARAM_BUFFERSIZE >> 9); - add_disk(aram_gendisk); + /* request interrupt */ + retval = request_irq(adev->irq, aram_irq_handler, + SA_INTERRUPT | SA_SHIRQ, + DRV_MODULE_NAME, adev); + if (retval) { + aram_printk(KERN_ERR, "request of irq%d failed\n", adev->irq); + goto out; + } - /* lock this since audio driver might be using it */ - local_irq_save(flags); - writew(readw(AI_DSP_CSR) | AI_CSR_ARINTMASK | AI_CSR_PIINT,AI_DSP_CSR); - local_irq_restore(flags); + /* enable ARAM interrupts, and route them to the processor */ + spin_lock_irqsave(&adev->io_lock, flags); + writew(readw(csr_reg) | DSP_CSR_ARINTMASK | DSP_CSR_PIINT, csr_reg); + spin_unlock_irqrestore(&adev->io_lock, flags); - refCount = 0; +out: + return retval; +} + +/* + * + */ +static void aram_exit_irq(struct aram_device *adev) +{ + aram_quiesce(adev); + + free_irq(adev->irq, adev); +} + +/* + * + */ +static int aram_init(struct aram_device *adev, + struct resource *mem, int irq) +{ + int retval; + + memset(adev, 0, sizeof(*adev) - sizeof(adev->pdev)); + + adev->io_base = (void __iomem *)mem->start; + adev->irq = irq; + + retval = aram_init_blk_dev(adev); + if (!retval) { + retval = aram_init_irq(adev); + if (retval) { + aram_exit_blk_dev(adev); + } + } + return retval; +} + +/* + * + */ +static void aram_exit(struct aram_device *adev) +{ + aram_exit_blk_dev(adev); + aram_exit_irq(adev); +} + +/* + * Needed for platform devices. + */ +static void aram_dev_release(struct device *dev) +{ +} + + +static struct resource aram_resources[] = { + [0] = { + .start = DSP_BASE, + .end = DSP_BASE + DSP_SIZE -1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ARAM_IRQ, + .end = ARAM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct aram_device aram_device = { + .pdev = { + .name = ARAM_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(aram_resources), + .resource = aram_resources, + .dev = { + .release = aram_dev_release, + }, + }, +}; + + +/* + * + */ +static int aram_probe(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + struct resource *mem; + int irq; + int retval; + + retval = -ENODEV; + irq = platform_get_irq(pdev, 0); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem) { + retval = aram_init(adev, mem, irq); + } + return retval; +} + +/* + * + */ +static int aram_remove(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + + aram_exit(adev); - printk("ARAM info: Size = %u,Mode = 0x%x,Refresh = %u\n", - readw(AR_SIZE),readw(AR_MODE),readl(AR_REFRESH)); - return 0; +} - out_queue: - del_gendisk(aram_gendisk); - put_disk(aram_gendisk); - out_disk: - unregister_blkdev(ARAM_MAJOR, DEVICE_NAME); - out_blkdev: - free_irq(ARAM_IRQ,IRQ_PARAM); - out_irq: - return ret; +/* + * + */ +static void aram_shutdown(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct aram_device *adev = to_aram_device(pdev); + + aram_quiesce(adev); } -void __exit aram_cleanup(void) + +static struct device_driver aram_driver = { + .name = ARAM_NAME, + .bus = &platform_bus_type, + .probe = aram_probe, + .remove = aram_remove, + .shutdown = aram_shutdown, +}; + + +/* + * + */ +static int __init aram_init_module(void) { - free_irq(ARAM_IRQ,IRQ_PARAM); + int retval = 0; - blk_unregister_region(MKDEV(ARAM_MAJOR, 0), 256); - - if (unregister_blkdev(ARAM_MAJOR, DEVICE_NAME) != 0) - printk(KERN_ERR DEVICE_NAME ": unregister of device failed\n"); - - del_gendisk(aram_gendisk); - put_disk(aram_gendisk); - blk_cleanup_queue(aram_queue); - - return; + aram_printk(KERN_INFO, "%s - version %s\n", DRV_DESCRIPTION, + aram_driver_version); + + retval = driver_register(&aram_driver); + if (!retval) { + retval = platform_device_register(&aram_device.pdev); + } + + return retval; } -MODULE_AUTHOR("Todd Jeffreys <to...@vo...>"); -MODULE_DESCRIPTION("Gamecube ARAM block driver"); +/* + * + */ +static void __exit aram_exit_module(void) +{ + platform_device_unregister(&aram_device.pdev); + driver_unregister(&aram_driver); +} + +module_init(aram_init_module); +module_exit(aram_exit_module); + + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); -module_init(aram_init); -module_exit(aram_cleanup); + |
From: <he...@us...> - 2005-03-20 17:10:48
|
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32317/drivers/exi Modified Files: exi-driver.c exi-hw.c exi-hw.h Log Message: The caller of exi_hw_init can now set the name used for registrations. Warn on deselects if the channel is not selected. Index: exi-driver.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-driver.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- exi-driver.c 15 Mar 2005 23:39:00 -0000 1.8 +++ exi-driver.c 20 Mar 2005 17:10:38 -0000 1.9 @@ -349,7 +349,7 @@ extern unsigned long exi_running; if (!test_and_set_bit(1, &exi_running)) { - retval = exi_hw_init(); + retval = exi_hw_init(DRV_MODULE_NAME); if (retval) goto err_hw_init; } Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- exi-hw.c 17 Mar 2005 21:02:15 -0000 1.7 +++ exi-hw.c 20 Mar 2005 17:10:38 -0000 1.8 @@ -435,6 +435,8 @@ { struct exi_channel *exi_channel = cmd->exi_channel; + WARN_ON(!exi_is_selected(exi_channel)); + DBG("channel=%d\n", exi_channel->channel); exi_deselect_raw(exi_channel); @@ -1086,7 +1088,7 @@ /* * Pseudo-Internal. Initialize basic channel structures and hardware. */ -int exi_hw_init(void) +int exi_hw_init(char *module_name) { struct exi_channel *exi_channel; int channel; @@ -1103,7 +1105,7 @@ exi_quiesce_all_channels(EXI_CSR_EXTINMASK); /* register the exi interrupt handler */ - retval = request_irq(EXI_IRQ, exi_irq_handler, 0, "exi", NULL); + retval = request_irq(EXI_IRQ, exi_irq_handler, 0, module_name, NULL); if (retval) { exi_printk(KERN_ERR, "unable to register irq%d\n", EXI_IRQ); } Index: exi-hw.h =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- exi-hw.h 15 Mar 2005 23:39:01 -0000 1.3 +++ exi-hw.h 20 Mar 2005 17:10:38 -0000 1.4 @@ -118,7 +118,7 @@ struct exi_event_handler events[EXI_MAX_EVENTS]; }; -extern int exi_hw_init(void); +extern int exi_hw_init(char *); extern void exi_hw_exit(void); #define exi_is_selected(x) ((x)->flags & EXI_SELECTED) |
From: <he...@us...> - 2005-03-20 17:10:47
|
Update of /cvsroot/gc-linux/linux/include/linux In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32317/include/linux Modified Files: exi.h Log Message: The caller of exi_hw_init can now set the name used for registrations. Warn on deselects if the channel is not selected. Index: exi.h =================================================================== RCS file: /cvsroot/gc-linux/linux/include/linux/exi.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- exi.h 13 Mar 2005 21:49:15 -0000 1.9 +++ exi.h 20 Mar 2005 17:10:39 -0000 1.10 @@ -283,7 +283,7 @@ int retval = 0; if (!test_and_set_bit(1, &exi_running)) { - retval = exi_hw_init(); + retval = exi_hw_init("exi-lite"); } return retval; } |
From: <he...@us...> - 2005-03-20 16:54:03
|
Update of /cvsroot/gc-linux/linux/arch/ppc/kernel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22613 Modified Files: cputable.c Log Message: Indeed, the cpu table was broken since 2.6.10 was merged. Index: cputable.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/kernel/cputable.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- cputable.c 17 Mar 2005 18:21:50 -0000 1.8 +++ cputable.c 20 Mar 2005 16:53:54 -0000 1.9 @@ -199,7 +199,7 @@ .cpu_setup = __setup_cpu_750 }, { /* 750CXe "Gekko" (83214) */ - .pvr_mask = 0xfffffff0, + .pvr_mask = 0xffffffff, .pvr_value = 0x00083214, .cpu_name = "750CXe", .cpu_features = CPU_FTR_COMMON | |
From: <he...@us...> - 2005-03-17 21:05:49
|
Update of /cvsroot/gc-linux/linux/drivers/net In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30820/drivers/net Modified Files: gcn-bba.c Log Message: Cosmetic change. We keep not refrigerating the bba io thread as may be used by the swsusp system (to suspend to a network block device for instance). Index: gcn-bba.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/net/gcn-bba.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- gcn-bba.c 13 Mar 2005 23:43:32 -0000 1.7 +++ gcn-bba.c 17 Mar 2005 21:05:39 -0000 1.8 @@ -737,18 +737,12 @@ { struct bba_private *priv = param; + set_user_nice(current, -20); current->flags |= PF_NOFREEZE; set_current_state(TASK_RUNNING); - set_user_nice(current, -20); - for(;;) { -#if 0 - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); - } -#endif - if (kthread_should_stop()) - break; + while(!kthread_should_stop()) { + //try_to_freeze(PF_FREEZE); wait_event(priv->io_waitq, priv->rx_work || priv->tx_skb); while (priv->rx_work || priv->tx_skb) { if (priv->rx_work) { |
From: <he...@us...> - 2005-03-17 21:02:27
|
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30376 Modified Files: exi-hw.c Log Message: Clean post_cmd only after a real use, and not everytime. Use DMA too for a corner case in the transfer function. Fixed the event triggering function, which I inadvertently broke. Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- exi-hw.c 15 Mar 2005 23:39:01 -0000 1.6 +++ exi-hw.c 17 Mar 2005 21:02:15 -0000 1.7 @@ -289,6 +289,7 @@ writel(readl(csr_reg) | EXI_CSR_TCINTMASK, csr_reg); spin_unlock_irqrestore(&exi_channel->io_lock, flags); + /* start the transfer */ writel(EXI_CR_TSTART | EXI_CR_DMA | (mode&7), io_base + EXI_CR); } @@ -459,6 +460,7 @@ cmd->done_data = post_cmd->done_data; cmd->done = post_cmd->done; + exi_op_nop(post_cmd, exi_channel); exi_command_done(cmd); } @@ -476,6 +478,8 @@ */ static int exi_cmd_transfer(struct exi_command *cmd) { + static u8 exi_aligned_transfer_buf[EXI_DMA_ALIGN+1] + __attribute__ ((aligned (EXI_DMA_ALIGN+1))); struct exi_channel *exi_channel = cmd->exi_channel; struct exi_command *post_cmd = &exi_channel->post_cmd; void *pre_data, *data, *post_data; @@ -524,21 +528,31 @@ len = post_data - data; /* - * Coalesce pre and post data transfers if no DMA transfer is done. + * Coalesce pre and post data transfers if no DMA transfer is possible. */ if (!len) { /* - * Maximum transfer size here is 62 bytes. - * - * XXX + * Maximum transfer size here is 31+31=62 bytes. + */ + + /* * On transfer sizes greater than or equal to 32 bytes - * we could optimize the transfer by performing a 32-byte + * we can optimize the transfer by performing a 32-byte * DMA transfer using a specially aligned temporary buffer, * followed by a non-DMA transfer for the remaining bytes. */ - exi_transfer_raw(exi_channel, pre_data, pre_len+post_len, - opcode); - goto done; + if ( pre_len + post_len > EXI_DMA_ALIGN ) { + post_len = pre_len + post_len - (EXI_DMA_ALIGN+1); + post_data = pre_data + EXI_DMA_ALIGN+1; + len = EXI_DMA_ALIGN+1; + data = exi_aligned_transfer_buf; + memcpy(data, pre_data, EXI_DMA_ALIGN+1); + pre_len = 0; + } else { + exi_transfer_raw(exi_channel, pre_data, + pre_len + post_len, opcode); + goto done; + } } /* @@ -565,8 +579,6 @@ post_cmd->done = cmd->done; cmd->done_data = NULL; cmd->done = exi_cmd_post_transfer; - } else { - exi_op_nop(post_cmd, exi_channel); } exi_channel->dma_cmd = cmd; @@ -815,10 +827,12 @@ static inline int exi_trigger_event(struct exi_channel *exi_channel, unsigned int event_id) { + struct exi_event_handler *event; exi_event_handler_t handler; int retval = 0; - handler = exi_channel->events[event_id].handler; + event = &exi_channel->events[event_id]; + handler = event->handler; if (handler) { retval = handler(exi_channel, event_id, event->data); } |
From: <a.o...@bl...> - 2005-03-17 20:37:33
|
On Thu, Mar 17, 2005 at 06:53:20PM +0100, Albert Herranz wrote: > Uhmm, when looking at the current table that's not > true for already existing entries. The table is really > not sorted by pvr_value. > > But looking at arch/ppc/kernel/misc.S I see that the > identify_cpu function stops on first match. So > specific entries (with a deeper mask) must be placed > _before_ more generic ones. > > So at the end you are right. Gekko must be put before > 745/755. > Correct. I couldn't have put that better :) > PS: Any comments about the recently commited EXI > framework? Haven't really looked at it. Probably later on during the day as I catch up with my swamp of mail :( |
From: <he...@us...> - 2005-03-17 18:22:00
|
Update of /cvsroot/gc-linux/linux/arch/ppc/kernel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16859 Modified Files: cputable.c Log Message: Moved "Gekko" before 745/755, as it has a pvr_value/pvr_mask more specific and cpu_specs table searchs stop on first match. Thanks to apgo for pointing that out. Index: cputable.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/kernel/cputable.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- cputable.c 13 Mar 2005 12:11:27 -0000 1.7 +++ cputable.c 17 Mar 2005 18:21:50 -0000 1.8 @@ -198,6 +198,20 @@ .num_pmcs = 4, .cpu_setup = __setup_cpu_750 }, + { /* 750CXe "Gekko" (83214) */ + .pvr_mask = 0xfffffff0, + .pvr_value = 0x00083214, + .cpu_name = "750CXe", + .cpu_features = CPU_FTR_COMMON | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | + CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | + CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, + .cpu_user_features = COMMON_PPC, + .icache_bsize = 32, + .dcache_bsize = 32, + .num_pmcs = 4, + .cpu_setup = __setup_cpu_750cx + }, { /* 745/755 */ .pvr_mask = 0xfffff000, .pvr_value = 0x00083000, @@ -254,20 +268,6 @@ .num_pmcs = 4, .cpu_setup = __setup_cpu_750cx }, - { /* 750CXe "Gekko" (83214) */ - .pvr_mask = 0xfffffff0, - .pvr_value = 0x00083214, - .cpu_name = "750CXe", - .cpu_features = CPU_FTR_COMMON | - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | - CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | - CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP, - .cpu_user_features = COMMON_PPC, - .icache_bsize = 32, - .dcache_bsize = 32, - .num_pmcs = 4, - .cpu_setup = __setup_cpu_750cx - }, { /* 750FX rev 1.x */ .pvr_mask = 0xffffff00, .pvr_value = 0x70000100, |
From: Albert H. <alb...@ya...> - 2005-03-17 17:53:28
|
--- Arthur Othieno <a.o...@bl...> wrote: > And in doing so, you just broke the enumeration. The > entries need > to be ordered by .pvr_value. That's why 750CXe > (Gekko) came before > "745/755". Uhmm, when looking at the current table that's not true for already existing entries. The table is really not sorted by pvr_value. But looking at arch/ppc/kernel/misc.S I see that the identify_cpu function stops on first match. So specific entries (with a deeper mask) must be placed _before_ more generic ones. So at the end you are right. Gekko must be put before 745/755. > Please revert. Thanks a lot for pointing that out. Cheers, Albert PS: Any comments about the recently commited EXI framework? ______________________________________________ Renovamos el Correo Yahoo!: ¡250 MB GRATIS! Nuevos servicios, más seguridad http://correo.yahoo.es |
From: <a.o...@bl...> - 2005-03-17 17:16:59
|
On Sun, Mar 13, 2005 at 04:11:32AM -0800, he...@us... wrote: > Update of /cvsroot/gc-linux/linux/arch/ppc/kernel > In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31180 > > Modified Files: > cputable.c > Log Message: > Rearranged to force diff to give us a human understandable patch. > And in doing so, you just broke the enumeration. The entries need to be ordered by .pvr_value. That's why 750CXe (Gekko) came before "745/755". Yes, looking at the patch against mainline is not obvious at first glance. I'd originally split this into two patches; one to do the re-ordering and another to add an entry for Gekko. I'll get around to pushing these to -mm/mainline RSN, as this is the least invasive code in the tree ;) Please revert. Arthur |
From: <he...@us...> - 2005-03-17 15:36:07
|
Update of /cvsroot/gc-linux/htdocs/xml/en In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13339 Modified Files: download.xml Log Message: Added "build number" and date to the Latest Kernel Build. Index: download.xml =================================================================== RCS file: /cvsroot/gc-linux/htdocs/xml/en/download.xml,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- download.xml 6 Dec 2004 13:59:20 -0000 1.11 +++ download.xml 17 Mar 2005 15:35:56 -0000 1.12 @@ -15,6 +15,8 @@ <h2>Latest Kernel Build</h2> + <p>(Build 9, 14 March 2005)</p> + <p>This build always has the latest features, but might not work reliably. You may choose between two different kernel images.</p> <p>The <a href="../down/isobel/zImage.nfs.dol">zImage.nfs.dol (~1 MB)</a> requires a NFS-served <a href="http://www.tldp.org/HOWTO/NFS-Root.html">root</a> filesystem, like vaguely described <a href="../down/zImage-nfs.isobel.txt">here</a>. If you are on Linux, and have already played with NFS, try this image.</p> |
From: <he...@us...> - 2005-03-15 23:39:17
|
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv515 Modified Files: exi-driver.c exi-hw.c exi-hw.h Log Message: Added some more comments to code. Do not initialize again channels while initializing devices. Rename cmd_lock to select_lock, so it becomes more intuitive. Fix possible race while invoking handlers. Do not touch TCINT related stuff while enabling or disabling TC events. Index: exi-driver.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-driver.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- exi-driver.c 13 Mar 2005 21:49:16 -0000 1.7 +++ exi-driver.c 15 Mar 2005 23:39:00 -0000 1.8 @@ -351,13 +351,12 @@ if (!test_and_set_bit(1, &exi_running)) { retval = exi_hw_init(); if (retval) - goto err_irq_init; + goto err_hw_init; } - /* initialize channels and devices */ + /* initialize devices */ for (channel = 0; channel < EXI_MAX_CHANNELS; ++channel) { exi_channel = to_exi_channel(channel); - exi_channel_init(exi_channel, channel); for (device = 0; device < EXI_DEVICES_PER_CHANNEL; ++device) { exi_device = &exi_devices[channel][device]; exi_device_init(exi_device, channel, device); @@ -387,7 +386,7 @@ device_unregister(&exi_bus_devices[channel]); } exi_hw_exit(); -err_irq_init: +err_hw_init: return retval; } Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- exi-hw.c 14 Mar 2005 19:54:54 -0000 1.5 +++ exi-hw.c 15 Mar 2005 23:39:01 -0000 1.6 @@ -89,27 +89,27 @@ [0] = { .channel = 0, .lock = SPIN_LOCK_UNLOCKED, - .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(0), + .select_lock = SPIN_LOCK_UNLOCKED, .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( exi_channels[0].wait_queue), }, [1] = { .channel = 1, .lock = SPIN_LOCK_UNLOCKED, - .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(1), + .select_lock = SPIN_LOCK_UNLOCKED, .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( exi_channels[1].wait_queue), }, [2] = { .channel = 2, .lock = SPIN_LOCK_UNLOCKED, - .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(2), + .select_lock = SPIN_LOCK_UNLOCKED, .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( exi_channels[2].wait_queue), }, @@ -160,7 +160,7 @@ exi_channel->channel = channel; spin_lock_init(&exi_channel->lock); - spin_lock_init(&exi_channel->cmd_lock); + spin_lock_init(&exi_channel->select_lock); spin_lock_init(&exi_channel->io_lock); exi_channel->io_base = EXI_IO_BASE(channel); init_waitqueue_head(&exi_channel->wait_queue); @@ -406,16 +406,14 @@ { struct exi_channel *exi_channel = cmd->exi_channel; struct exi_device *exi_device; - //struct exi_driver *exi_driver; BUG_ON(cmd->data == NULL); BUG_ON(exi_is_selected(exi_channel)); - spin_lock(&exi_channel->cmd_lock); + spin_lock(&exi_channel->select_lock); /* cmd->data contains the device to select */ exi_device = cmd->data; - //exi_driver = to_exi_driver(exi_device->dev.driver); exi_channel->device_selected = exi_device; exi_channel->flags |= EXI_SELECTED; @@ -443,7 +441,7 @@ exi_channel->flags &= ~EXI_SELECTED; exi_channel->device_selected = NULL; - spin_unlock(&exi_channel->cmd_lock); + spin_unlock(&exi_channel->select_lock); } /* @@ -507,13 +505,14 @@ /* * |_______________|______...______|_______________| DMA alignment - * <----------------- len -----------------> + * <--pre_len--><---- len -----><-post_len-> * +-----------+------...------+-----------+ * | pre_data | data | post_data | * | non-DMA | DMA | non-DMA | * +-----------+------...------+-----------+ * < 32 bytes N*32 bytes < 32 bytes * |<--------->|<-----...----->|<--------->| + * <-------------- cmd->len ---------------> */ pre_data = data; @@ -816,13 +815,14 @@ static inline int exi_trigger_event(struct exi_channel *exi_channel, unsigned int event_id) { - struct exi_event_handler *event; + exi_event_handler_t handler; + int retval = 0; - event = &exi_channel->events[event_id]; - if (event->handler) { - return event->handler(exi_channel, event_id, event->data); + handler = exi_channel->events[event_id].handler; + if (handler) { + retval = handler(exi_channel, event_id, event->data); } - return 0; + return retval; } /* @@ -941,7 +941,7 @@ writel(csr | (EXI_CSR_EXTIN | EXI_CSR_EXTINMASK), csr_reg); break; case EXI_EVENT_TC: - writel(csr | (EXI_CSR_TCINT | EXI_CSR_TCINTMASK), csr_reg); + //writel(csr | (EXI_CSR_TCINT | EXI_CSR_TCINTMASK), csr_reg); break; case EXI_EVENT_IRQ: writel(csr | (EXI_CSR_EXIINT | EXI_CSR_EXIINTMASK), csr_reg); @@ -970,7 +970,7 @@ writel((csr | EXI_CSR_EXTIN) & ~EXI_CSR_EXTINMASK, csr_reg); break; case EXI_EVENT_TC: - writel((csr | EXI_CSR_TCINT) & ~EXI_CSR_TCINTMASK, csr_reg); + //writel((csr | EXI_CSR_TCINT) & ~EXI_CSR_TCINTMASK, csr_reg); break; case EXI_EVENT_IRQ: writel((csr | EXI_CSR_EXIINT) & ~EXI_CSR_EXIINTMASK, csr_reg); @@ -1070,7 +1070,7 @@ } /* - * Pseudo-Internal. Initialize + * Pseudo-Internal. Initialize basic channel structures and hardware. */ int exi_hw_init(void) { @@ -1085,6 +1085,7 @@ exi_channel_init(exi_channel, channel); } + /* calm down the hardware and allow external insertions */ exi_quiesce_all_channels(EXI_CSR_EXTINMASK); /* register the exi interrupt handler */ @@ -1097,7 +1098,7 @@ } /* - * Pseudo-Internal. + * Pseudo-Internal. */ void exi_hw_exit(void) { Index: exi-hw.h =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- exi-hw.h 14 Mar 2005 19:47:10 -0000 1.2 +++ exi-hw.h 15 Mar 2005 23:39:01 -0000 1.3 @@ -88,28 +88,27 @@ struct exi_event_handler { exi_event_handler_t handler; void *data; - unsigned int channel_mask; /* channels used by the handler */ + unsigned int channel_mask; /* channels used by handler */ }; /* * This structure represents an exi channel. */ struct exi_channel { - spinlock_t lock; + spinlock_t lock; /* misc channel lock */ int channel; unsigned long flags; #define EXI_SELECTED (1<<0) #define EXI_DMABUSY (1<<1) - spinlock_t io_lock; + spinlock_t io_lock; /* serializes access to CSR */ void __iomem *io_base; + spinlock_t select_lock; /* held while using channel */ struct exi_device *device_selected; wait_queue_head_t wait_queue; - spinlock_t cmd_lock; - struct exi_command *dma_cmd; struct exi_command post_cmd; |
From: <he...@us...> - 2005-03-15 00:14:40
|
Update of /cvsroot/gc-linux/htdocs/xml/en In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29507 Modified Files: news.xml Log Message: 15 March 2005, New improved EXI framework Index: news.xml =================================================================== RCS file: /cvsroot/gc-linux/htdocs/xml/en/news.xml,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- news.xml 14 Mar 2005 20:21:17 -0000 1.32 +++ news.xml 15 Mar 2005 00:14:31 -0000 1.33 @@ -2,6 +2,11 @@ <?xml-stylesheet href="news.xsl" type="text/xsl"?> <news> <item> + <date>15 March 2005</date> + <title>New improved EXI framework</title> + <text>A new kernel Expansion Interface subsystem is available on CVS. It is a code rewrite based on apgo's original driver model framework and some of Scream|CT's recent contributions. The good news is that the RTC and BBA drivers are using now the new framework and cpu usage is much lower. The not so good news is that we've dropped temporarily the memcard and SD drivers while they get reworked. The new stuff is already included in the <a href="docs/download.html">Latest Kernel Build</a>, updated to 2.6.11.</text> + </item> + <item> <date>14 March 2005</date> <title>YAGCD updated</title> <text>groepaz posted another update to the world famous non-official GameCube technical documentation. Available as usual <a href="docs/yagcd.html">here</a>.</text> |
From: <he...@us...> - 2005-03-14 20:21:29
|
Update of /cvsroot/gc-linux/htdocs/xml/en In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32477 Modified Files: news.xml Log Message: 14 March 2005, YAGCD updated Index: news.xml =================================================================== RCS file: /cvsroot/gc-linux/htdocs/xml/en/news.xml,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- news.xml 8 Jan 2005 00:55:32 -0000 1.31 +++ news.xml 14 Mar 2005 20:21:17 -0000 1.32 @@ -2,6 +2,11 @@ <?xml-stylesheet href="news.xsl" type="text/xsl"?> <news> <item> + <date>14 March 2005</date> + <title>YAGCD updated</title> + <text>groepaz posted another update to the world famous non-official GameCube technical documentation. Available as usual <a href="docs/yagcd.html">here</a>.</text> + </item> + <item> <date>8 January 2005</date> <title>Latest kernel build updated to 2.6.10</title> <text>This latest release includes Rob's preliminary read-only support for SD cards. Available at the <a href="docs/download.html">Latest Kernel Build</a> section of the download page.</text> |
From: <he...@us...> - 2005-03-14 19:55:03
|
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25235/drivers/exi Modified Files: exi-hw.c Log Message: Damn macros. Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- exi-hw.c 14 Mar 2005 19:47:10 -0000 1.4 +++ exi-hw.c 14 Mar 2005 19:54:54 -0000 1.5 @@ -411,7 +411,7 @@ BUG_ON(cmd->data == NULL); BUG_ON(exi_is_selected(exi_channel)); - spin_lock(exi_channel->cmd_lock); + spin_lock(&exi_channel->cmd_lock); /* cmd->data contains the device to select */ exi_device = cmd->data; @@ -443,7 +443,7 @@ exi_channel->flags &= ~EXI_SELECTED; exi_channel->device_selected = NULL; - spin_unlock(exi_channel->cmd_lock); + spin_unlock(&exi_channel->cmd_lock); } /* |
From: <he...@us...> - 2005-03-14 19:47:20
|
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22829/drivers/exi Modified Files: exi-hw.h exi-hw.c Log Message: Fixed issue if kernel preemption is enabled. Index: exi-hw.h =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- exi-hw.h 13 Mar 2005 21:49:16 -0000 1.1 +++ exi-hw.h 14 Mar 2005 19:47:10 -0000 1.2 @@ -106,12 +106,13 @@ void __iomem *io_base; struct exi_device *device_selected; + wait_queue_head_t wait_queue; + + spinlock_t cmd_lock; struct exi_command *dma_cmd; struct exi_command post_cmd; - wait_queue_head_t wait_queue; - unsigned long csr; struct tasklet_struct tasklet; Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- exi-hw.c 13 Mar 2005 21:49:16 -0000 1.3 +++ exi-hw.c 14 Mar 2005 19:47:10 -0000 1.4 @@ -89,6 +89,7 @@ [0] = { .channel = 0, .lock = SPIN_LOCK_UNLOCKED, + .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(0), .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( @@ -97,6 +98,7 @@ [1] = { .channel = 1, .lock = SPIN_LOCK_UNLOCKED, + .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(1), .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( @@ -105,6 +107,7 @@ [2] = { .channel = 2, .lock = SPIN_LOCK_UNLOCKED, + .cmd_lock = SPIN_LOCK_UNLOCKED, .io_lock = SPIN_LOCK_UNLOCKED, .io_base = EXI_IO_BASE(2), .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER( @@ -157,6 +160,7 @@ exi_channel->channel = channel; spin_lock_init(&exi_channel->lock); + spin_lock_init(&exi_channel->cmd_lock); spin_lock_init(&exi_channel->io_lock); exi_channel->io_base = EXI_IO_BASE(channel); init_waitqueue_head(&exi_channel->wait_queue); @@ -407,6 +411,8 @@ BUG_ON(cmd->data == NULL); BUG_ON(exi_is_selected(exi_channel)); + spin_lock(exi_channel->cmd_lock); + /* cmd->data contains the device to select */ exi_device = cmd->data; //exi_driver = to_exi_driver(exi_device->dev.driver); @@ -436,6 +442,8 @@ exi_channel->flags &= ~EXI_SELECTED; exi_channel->device_selected = NULL; + + spin_unlock(exi_channel->cmd_lock); } /* |
From: <he...@us...> - 2005-03-13 23:43:42
|
Update of /cvsroot/gc-linux/linux/drivers/net In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv825/drivers/net Modified Files: gcn-bba.c Log Message: Modified the bba io thread to run at higher prio. We need to run as quick as possible to service the network layer. Index: gcn-bba.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/net/gcn-bba.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- gcn-bba.c 13 Mar 2005 21:52:55 -0000 1.6 +++ gcn-bba.c 13 Mar 2005 23:43:32 -0000 1.7 @@ -739,6 +739,7 @@ current->flags |= PF_NOFREEZE; set_current_state(TASK_RUNNING); + set_user_nice(current, -20); for(;;) { #if 0 |
From: <he...@us...> - 2005-03-13 21:53:55
|
Update of /cvsroot/gc-linux/linux/drivers/block In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5993/drivers/block Modified Files: Kconfig Log Message: Marked the memcard and sd drivers as broken. Index: Kconfig =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/block/Kconfig,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- Kconfig 3 Mar 2005 21:12:50 -0000 1.11 +++ Kconfig 13 Mar 2005 21:53:32 -0000 1.12 @@ -74,7 +74,7 @@ config GAMECUBE_MEMCARD tristate "Nintendo GameCube memory card (EXPERIMENTAL)" - depends on GAMECUBE && EXI && EXPERIMENTAL + depends on GAMECUBE && EXI && EXPERIMENTAL && BROKEN help This enables support for using memory cards compatible with the Nintendo GameCube. @@ -85,7 +85,7 @@ config GAMECUBE_SD tristate "Nintendo GameCube SD and MMC memory card (EXPERIMENTAL)" - depends on GAMECUBE && EXI && EXPERIMENTAL + depends on GAMECUBE && EXI && EXPERIMENTAL && BROKEN help This enables support for SD and MMC cards WARNING: driver is in alpha stage. Only reading supported. Card |
From: <he...@us...> - 2005-03-13 21:53:32
|
Update of /cvsroot/gc-linux/linux/drivers/net In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5665/drivers/net Modified Files: gcn-bba.c Log Message: Modified the bba driver so it works with the new exi framework. Index: gcn-bba.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/net/gcn-bba.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- gcn-bba.c 13 Jan 2005 01:55:32 -0000 1.5 +++ gcn-bba.c 13 Mar 2005 21:52:55 -0000 1.6 @@ -1,9 +1,10 @@ -/* +/** * drivers/net/gcn-bba.c * * Nintendo GameCube Broadband Adapter driver * Copyright (C) 2004-2005 The GameCube Linux Team - * Copyright (C) 2004,2005 Albert Herranz,Todd Jeffreys + * Copyright (C) 2005 Todd Jeffreys + * Copyright (C) 2004,2005 Albert Herranz * * Based on previous work by Stefan Esser, Franz Lehner, Costis and tmbinc. [...1928 lines suppressed...] /** + * bba_exit_module - driver exit routine + * + * Removes the BroadBand Adapter driver module. * */ static void __exit bba_exit_module(void) { - exi_unregister_driver(&bba_exi_driver); + exi_driver_unregister(&bba_driver); } module_init(bba_init_module); module_exit(bba_exit_module); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_LICENSE("GPL"); + |
From: <he...@us...> - 2005-03-13 21:52:20
|
Update of /cvsroot/gc-linux/linux/arch/ppc/platforms In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5073/arch/ppc/platforms Modified Files: Makefile gamecube.c gcn-rtc.c Log Message: Disabled building the reset driver as a module, as currently can't be. Modified the RTC driver to work with the new exi framework. Index: Makefile =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/platforms/Makefile,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- Makefile 3 Mar 2005 21:12:49 -0000 1.16 +++ Makefile 13 Mar 2005 21:51:39 -0000 1.17 @@ -43,7 +43,8 @@ obj-$(CONFIG_SBC82xx) += sbc82xx.o obj-$(CONFIG_SPRUCE) += spruce.o obj-$(CONFIG_LITE5200) += lite5200.o mpc5200.o -obj-$(CONFIG_GAMECUBE) += gamecube.o gcn-rtc.o +obj-$(CONFIG_GAMECUBE) += gamecube.o +obj-$(CONFIG_GAMECUBE_RTC) += gcn-rtc.o obj-$(CONFIG_GAMECUBE_CONSOLE) += gcn-con.o obj-$(CONFIG_GAMECUBE_RESET) += gcn-rsw.o obj-$(CONFIG_GAMECUBE_DVDCOVER) += gcn-dvdcover.o Index: gamecube.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/platforms/gamecube.c,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- gamecube.c 8 Jan 2005 22:46:47 -0000 1.31 +++ gamecube.c 13 Mar 2005 21:51:39 -0000 1.32 @@ -206,9 +206,4 @@ ppc_md.machine_kexec_prepare = gamecube_kexec_prepare; ppc_md.machine_kexec = machine_kexec_simple; #endif /* CONFIG_KEXEC */ - - /* no RTC driver, too slow */ - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = NULL; - ppc_md.get_rtc_time = NULL; } Index: gcn-rtc.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/platforms/gcn-rtc.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- gcn-rtc.c 8 Jan 2005 22:46:47 -0000 1.2 +++ gcn-rtc.c 13 Mar 2005 21:51:39 -0000 1.3 @@ -1,8 +1,9 @@ /* * arch/ppc/platforms/gcn-rtc.c * - * Nintendo GameCube RTC functions - * Copyright (C) 2004 The GameCube Linux Team + * Nintendo GameCube RTC/SRAM functions + * Copyright (C) 2004-2005 The GameCube Linux Team + * Copyright (C) 2005 Albert Herranz * * Based on gamecube_time.c from Torben Nielsen. * @@ -15,147 +16,222 @@ #include <linux/init.h> #include <linux/time.h> + #include <linux/exi.h> -/* - * The EXI functions that we use are guaranteed to work by the gcn-exi-lite - * framework even if exi_lite_init() has not been called. - */ +#define DRV_MODULE_NAME "gcn-rtc" +#define DRV_DESCRIPTION "Nintendo GameCube RTC/SRAM driver" +#define DRV_AUTHOR "Albert Herranz" -#define RTC_OFFSET 946684800L +static char rtc_driver_version[] = "1.0"; -static int rtc_probe(struct exi_device *); -static void rtc_remove(struct exi_device *); +#define rtc_printk(level, format, arg...) \ + printk(level DRV_MODULE_NAME ": " format , ## arg) -static int bias = 0; -static int initialized = 0; -static struct exi_driver rtc_exi_driver = { - .name = "RTC/SRAM", - .eid = { - .channel = 0, - .device = 1, - .id = 0xFFFF1698 - }, - .frequency = 3, - .probe = rtc_probe, - .remove = rtc_remove + +#define RTC_EXI_ID 0xFFFF1698 + +#define RTC_EXI_CHANNEL 0 +#define RTC_EXI_DEVICE 1 +#define RTC_EXI_FREQ 3 /* 8MHz */ + +#define RTC_OFFSET 946684800L + + +struct gcn_sram { + u16 csum1; + u16 csum2; + u32 ead0; + u32 ead1; + int bias; + s8 horz_display_offset; + u8 ntd; + u8 language; + u8 flags; + u8 reserved[44]; }; -#if 0 -static void read_sram(unsigned char *abuf) +struct rtc_private { + spinlock_t lock; + struct exi_device *dev; + + struct gcn_sram sram; +}; + +static struct rtc_private rtc_private; + +/* + * Loads the SRAM contents. + */ +static void sram_load(struct exi_device *dev) { - unsigned long a; - + struct rtc_private *priv = exi_get_drvdata(dev); + struct gcn_sram *sram = &priv->sram; + u32 req; + /* select the SRAM device */ - exi_select(0, 1, 3); + exi_dev_select(dev); /* send the appropriate command */ - a = 0x20000100; - exi_write(0, &a, 4); + req = 0x20000100; + exi_dev_write(dev, &req, sizeof(req)); /* read the SRAM data */ - exi_read(0, abuf, 64); + exi_dev_read(dev, sram, sizeof(*sram)); /* deselect the SRAM device */ - exi_deselect(0); + exi_dev_deselect(dev); return; } -static unsigned long get_rtc(void) +/* + * Gets the hardware clock date and time. + */ +static unsigned long rtc_get_time(struct exi_device *dev) { - unsigned long a = 0L; + unsigned long a; /* select the RTC device */ - exi_select(0, 1, 3); + exi_dev_select(dev); /* send the appropriate command */ a = 0x20000000; - exi_write(0, &a, 4); + exi_dev_write(dev, &a, sizeof(a)); /* read the time and date value */ - exi_read(0, &a, 4); + exi_dev_read(dev, &a, sizeof(a)); /* deselect the RTC device */ - exi_deselect(0); + exi_dev_deselect(dev); return a; } -static void set_rtc(unsigned long aval) +/* + * Sets the hardware clock date and time to @aval. + */ +static void rtc_set_time(struct exi_device *dev, unsigned long aval) { - unsigned long a; + u32 req; /* select the RTC device */ - exi_select(0, 1, 3); + exi_dev_select(dev); /* send the appropriate command */ - a = 0xA0000000; - exi_write(0, &a, 4); + req = 0xa0000000; + exi_dev_write(dev, &req, sizeof(req)); - /* Set the new time and date value */ - exi_write(0, &aval, 4); + /* set the new time and date value */ + exi_dev_write(dev, &aval, sizeof(aval)); - /* Deselect the RTC device */ - exi_deselect(0); + /* deselect the RTC device */ + exi_dev_deselect(dev); } -#endif + /** - * + * Platform specific function to return the current date and time. */ -unsigned long gcn_get_rtc_time(void) +static unsigned long gcn_get_rtc_time(void) { - static int i=0; - if (i++ == 0) { - printk(KERN_INFO "Get RTC time\n"); - } - if (initialized) { - //return get_rtc() + bias + RTC_OFFSET; - } - return 0; + struct rtc_private *priv = &rtc_private; + + return rtc_get_time(priv->dev) + priv->sram.bias + RTC_OFFSET; } /** + * Platform specific function to set the current date and time. * */ -int gcn_set_rtc_time(unsigned long nowtime) +static int gcn_set_rtc_time(unsigned long nowtime) { - printk(KERN_INFO "Set RTC time %lu\n",nowtime); - if (initialized) { - //set_rtc(nowtime - RTC_OFFSET - bias); - return 0; - } - - return 0; -} + struct rtc_private *priv = &rtc_private; -static int rtc_probe(struct exi_device *dev) -{ - /* nothing to probe, hardware is always there */ - initialized = 1; - - return 0; + rtc_set_time(priv->dev, nowtime - RTC_OFFSET - priv->sram.bias); + + return 1; } +/** + * + */ static void rtc_remove(struct exi_device *dev) { - initialized = 0; + struct rtc_private *priv = exi_get_drvdata(dev); + unsigned long flags; + + if (priv) { + spin_lock_irqsave(&priv->lock, flags); + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + spin_unlock_irqrestore(&priv->lock, flags); + } + exi_device_put(dev); } /** * */ -long gcn_time_init(void) +static int rtc_probe(struct exi_device *dev) { - printk(KERN_INFO "gcn_time_init\n"); - initialized = 0; - return 0; - //return exi_register_driver(&rtc_exi_driver); + struct rtc_private *priv = &rtc_private; + unsigned long flags; + int retval = -ENODEV; + + if (exi_device_get(dev)) { + spin_lock_init(&priv->lock); + + exi_set_drvdata(dev, priv); + priv->dev = dev; + + memset(&priv->sram, 0, sizeof(struct gcn_sram)); + sram_load(dev); + + spin_lock_irqsave(&priv->lock, flags); + ppc_md.set_rtc_time = gcn_set_rtc_time; + ppc_md.get_rtc_time = gcn_get_rtc_time; + spin_unlock_irqrestore(&priv->lock, flags); + + retval = 0; + } + + return retval; } - /* -char sram[64]; - int *pbias = (int *)&sram[0xC]; - read_sram(sram); - bias = *pbias; - return 0; */ + +static struct exi_device_id rtc_eid_table[] = { + [0] = { + .channel = RTC_EXI_CHANNEL, + .device = RTC_EXI_DEVICE, + .id = RTC_EXI_ID + }, + { .id = 0 } +}; + +static struct exi_driver rtc_driver = { + .name = "gcn-rtc", + .eid_table = rtc_eid_table, + .frequency = RTC_EXI_FREQ, + .probe = rtc_probe, + .remove = rtc_remove, +}; + +static int __init rtc_init_module(void) +{ + rtc_printk(KERN_INFO, "%s - version %s\n", + DRV_DESCRIPTION, rtc_driver_version); + + return exi_driver_register(&rtc_driver); +} + +static void __exit rtc_exit_module(void) +{ + exi_driver_unregister(&rtc_driver); +} + +module_init(rtc_init_module); +module_exit(rtc_exit_module); + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_LICENSE("GPL"); |
From: <he...@us...> - 2005-03-13 21:52:19
|
Update of /cvsroot/gc-linux/linux/arch/ppc/configs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5073/arch/ppc/configs Modified Files: gamecube_defconfig Log Message: Disabled building the reset driver as a module, as currently can't be. Modified the RTC driver to work with the new exi framework. Index: gamecube_defconfig =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/configs/gamecube_defconfig,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- gamecube_defconfig 3 Mar 2005 21:12:49 -0000 1.26 +++ gamecube_defconfig 13 Mar 2005 21:51:37 -0000 1.27 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.11 -# Thu Mar 3 15:49:42 2005 +# Sun Mar 13 22:29:43 2005 # CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y @@ -107,6 +107,7 @@ # CONFIG_ADS8272 is not set # CONFIG_PQ2FADS is not set # CONFIG_LITE5200 is not set +CONFIG_GAMECUBE_RTC=y # CONFIG_GAMECUBE_CONSOLE is not set CONFIG_GAMECUBE_RESET=y CONFIG_GAMECUBE_DVDCOVER=y @@ -180,8 +181,6 @@ # # CONFIG_BLK_DEV_FD is not set # CONFIG_GAMECUBE_ARAM is not set -# CONFIG_GAMECUBE_MEMCARD is not set -# CONFIG_GAMECUBE_SD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set |
From: <he...@us...> - 2005-03-13 21:52:15
|
Update of /cvsroot/gc-linux/linux/arch/ppc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5073/arch/ppc Modified Files: Kconfig Log Message: Disabled building the reset driver as a module, as currently can't be. Modified the RTC driver to work with the new exi framework. Index: Kconfig =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/ppc/Kconfig,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- Kconfig 3 Mar 2005 21:12:48 -0000 1.23 +++ Kconfig 13 Mar 2005 21:51:37 -0000 1.24 @@ -651,6 +651,16 @@ depends on ADS8272 default y +config GAMECUBE_RTC + bool "Nintendo GameCube Real Time Clock and SRAM" + depends on GAMECUBE && EXI + default y + help + If you say yes to this option, support will be included for the + Real Time Clock and SRAM of the Nintendo GameCube. + + If in doubt, say Y here. + config GAMECUBE_CONSOLE bool "Nintendo GameCube debug console" depends on GAMECUBE @@ -662,16 +672,13 @@ If in doubt, say N here. config GAMECUBE_RESET - tristate "Nintendo GameCube reset button" + bool "Nintendo GameCube reset button" depends on GAMECUBE default y help If you say yes to this option, support will be included for the reset button of the Nintendo GameCube. - This driver can also be built as a module. If so, the module - will be called gcn-rsw. - If in doubt, say Y here. config GAMECUBE_DVDCOVER |
Update of /cvsroot/gc-linux/linux/drivers/exi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4397/drivers/exi Modified Files: Makefile exi-driver.c exi-hw.c Added Files: exi-hw.h Removed Files: exi-bus.c exi_priv.h gcn-exi-lite-tmbinc-exi_c.c gcn-exi-lite.c gcn-exi-lite.h Log Message: Added yet another EXI Layer Framework. --- NEW FILE: exi-hw.h --- /* * drivers/exi/exi-hw.h * * Nintendo GameCube EXpansion Interface support. Hardware routines. * Copyright (C) 2004-2005 The GameCube Linux Team * Copyright (C) 2004,2005 Todd Jeffreys <to...@vo...> * Copyright (C) 2005 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #ifndef __EXI_HW_H #define __EXI_HW_H #include <linux/interrupt.h> #include <asm/atomic.h> #include <linux/exi.h> #define exi_printk(level, format, arg...) \ printk(level "exi: " format , ## arg) #define EXI_MAX_CHANNELS 3 /* channels on the EXI bus */ #define EXI_DEVICES_PER_CHANNEL 3 /* number of devices per EXI channel */ #define EXI_MAX_EVENTS 3 /* types of events on the EXI bus */ #define EXI_MAX_FREQ 7 #define EXI_FREQ_SCAN 3 #define EXI_READ 0 #define EXI_WRITE 1 #define EXI_IRQ 4 #define EXI_DMA_ALIGN 0x1f /* 32 bytes */ #define EXI_BASE 0xcc006800 #define EXI_SIZE 0x40 #define EXI_CHANNEL_SPACING 0x14 #define EXI_IO_BASE(c) ((void __iomem *)(EXI_BASE + ((c)*EXI_CHANNEL_SPACING))) #define EXI_CSR 0x00 #define EXI_CSR_EXIINTMASK (1<<0) #define EXI_CSR_EXIINT (1<<1) #define EXI_CSR_TCINTMASK (1<<2) #define EXI_CSR_TCINT (1<<3) #define EXI_CSR_CLKMASK (0x7<<4) #define EXI_CSR_CLK_1MHZ (0x0<<4) #define EXI_CSR_CLK_2MHZ (0x1<<4) #define EXI_CSR_CLK_4MHZ (0x2<<4) #define EXI_CSR_CLK_8MHZ (0x3<<4) #define EXI_CSR_CLK_16MHZ (0x4<<4) #define EXI_CSR_CLK_32MHZ (0x5<<4) #define EXI_CSR_CSMASK (0x7<<7) #define EXI_CSR_CS_0 (0x1<<7) /* Chip Select 001 */ #define EXI_CSR_CS_1 (0x2<<7) /* Chip Select 010 */ #define EXI_CSR_CS_2 (0x4<<7) /* Chip Select 100 */ #define EXI_CSR_EXTINMASK (1<<10) #define EXI_CSR_EXTIN (1<<11) #define EXI_CSR_EXT (1<<12) #define EXI_MAR 0x04 #define EXI_LENGTH 0x08 #define EXI_CR 0x0c #define EXI_CR_TSTART (1<<0) #define EXI_CR_DMA (1<<1) #define EXI_CR_READ (0<<2) #define EXI_CR_WRITE (1<<2) #define EXI_CR_READ_WRITE (2<<2) #define EXI_CR_TLEN(len) (((len)-1)<<4) #define EXI_DATA 0x10 /* * For registering event handlers with the exi layer. */ struct exi_event_handler { exi_event_handler_t handler; void *data; unsigned int channel_mask; /* channels used by the handler */ }; /* * This structure represents an exi channel. */ struct exi_channel { spinlock_t lock; int channel; unsigned long flags; #define EXI_SELECTED (1<<0) #define EXI_DMABUSY (1<<1) spinlock_t io_lock; void __iomem *io_base; struct exi_device *device_selected; struct exi_command *dma_cmd; struct exi_command post_cmd; wait_queue_head_t wait_queue; unsigned long csr; struct tasklet_struct tasklet; struct exi_event_handler events[EXI_MAX_EVENTS]; }; extern int exi_hw_init(void); extern void exi_hw_exit(void); #define exi_is_selected(x) ((x)->flags & EXI_SELECTED) /* * Internal. * Declare simple transfer functions for single bytes, words and dwords, * and build a general transfer function based on that. */ #define __declare__exi_transfer_raw(_type,_val,_data,_on_write,_on_read) \ static inline void __exi_transfer_raw_##_type(struct exi_channel *exi_channel,\ _type *_data, int mode) \ { \ u32 __iomem *csr_reg = exi_channel->io_base + EXI_CSR; \ u32 __iomem *data_reg = exi_channel->io_base + EXI_DATA; \ u32 __iomem *cr_reg = exi_channel->io_base + EXI_CR; \ u32 _val = ~0; \ unsigned long flags; \ \ /* \ * On reads we write too some known value to EXIxDATA because \ * information currently stored there is leaked to the \ * MOSI line, confusing some hardware. \ */ \ if (mode & EXI_OP_WRITE) \ _on_write; \ writel(_val, data_reg); \ \ /* start transfer */ \ _val = EXI_CR_TSTART | EXI_CR_TLEN(sizeof(_type)) | (mode&7); \ writel(_val, cr_reg); \ \ /* wait for transfer completion */ \ while(readl(cr_reg) & EXI_CR_TSTART) \ cpu_relax(); \ \ /* XXX check if we need that on immediate mode */ \ /* assert transfer complete interrupt */ \ spin_lock_irqsave(&exi_channel->io_lock, flags); \ writel(readl(csr_reg) | EXI_CSR_TCINT, csr_reg); \ spin_unlock_irqrestore(&exi_channel->io_lock, flags); \ \ if (!(mode & EXI_OP_WRITE)) { \ _val = readl(data_reg); \ _on_read; \ } \ } #define __declare__exi_transfer_raw_simple(_type) \ __declare__exi_transfer_raw( \ _type, _v, _d, \ _v = *(_d) << (32 - (8*sizeof(_type))), \ *(_d) = (_type)(_v >> (32 - (8*sizeof(_type)))) \ ) __declare__exi_transfer_raw_simple(u8) __declare__exi_transfer_raw_simple(u16) __declare__exi_transfer_raw_simple(u32) #endif /* __EXI_HW_H */ Index: Makefile =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/Makefile,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- Makefile 8 Jan 2005 22:46:47 -0000 1.3 +++ Makefile 13 Mar 2005 21:49:16 -0000 1.4 @@ -2,4 +2,4 @@ # Makefile for the EXI bus core. # -obj-$(CONFIG_EXI) += exi-bus.o exi-hw.o +obj-$(CONFIG_EXI) += exi-driver.o exi-hw.o Index: exi-driver.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-driver.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- exi-driver.c 19 Oct 2004 22:49:40 -0000 1.6 +++ exi-driver.c 13 Mar 2005 21:49:16 -0000 1.7 @@ -2,8 +2,10 @@ * drivers/exi/exi-driver.c * * Nintendo GameCube Expansion Interface support. Driver model routines. + * Copyright (C) 2004-2005 The GameCube Linux Team * Copyright (C) 2004 Arthur Othieno <a.o...@bl...> - * Copyright (C) 2004 The GameCube Linux Team + * Copyright (C) 2004,2005 Todd Jeffreys <to...@vo...> + * Copyright (C) 2005 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,113 +14,395 @@ * */ -#define DEBUG - +#include <linux/module.h> #include <linux/init.h> -#include <linux/errno.h> -#include <linux/kernel.h> #include <linux/device.h> #include <linux/exi.h> +#include <linux/delay.h> -static int exi_device_probe(struct device *dev) +#define DRV_MODULE_NAME "exi-driver" +#define DRV_DESCRIPTION "Nintendo GameCube EXpansion Interface driver" +#define DRV_AUTHOR "Arthur Othieno <a.o...@bl...>, " \ + "Todd Jeffreys <to...@vo...>, " \ + "Albert Herranz" + +static char exi_driver_version[] = "3.0"; + + +extern struct device exi_bus_devices[EXI_MAX_CHANNELS]; +extern struct exi_device exi_devices[EXI_MAX_CHANNELS][EXI_DEVICES_PER_CHANNEL]; + + +struct exi_map_id_to_name { + unsigned int id; + char *name; +}; + +static struct exi_map_id_to_name exi_map_id_to_name[] = { + { .id = EXI_ID_NONE, .name = "(external card)" }, + { .id = 0xffff1698, .name = "Mask ROM/RTC/SRAM/UART" }, + { .id = 0x00000004, .name = "Memory Card 59" }, + { .id = 0x00000008, .name = "Memory Card 123" }, + { .id = 0x00000010, .name = "Memory Card 251" }, + { .id = 0x00000020, .name = "Memory Card 507" }, + { .id = 0x00000040, .name = "Memory Card 1019" }, + { .id = 0x00000080, .name = "Memory Card 2043" }, + { .id = 0x01010000, .name = "USB Adapter" }, + { .id = 0x01020000, .name = "NPDP GDEV" }, + { .id = 0x05070000, .name = "IS Viewer" }, + { .id = 0x04120000, .name = "AD16" }, + { .id = 0x03010000, .name = "Marlin?" }, + { .id = 0x02020000, .name = "Modem" }, + { .id = 0x04020200, .name = "BroadBand Adapter" }, + { .id = 0 } +}; + +/* + * Internal. Return the friendly name of an exi identifier. + */ +static const char *exi_name_id(unsigned int id) { - struct exi_dev *exi_dev = to_exi_dev(dev); - struct exi_driver *drv = to_exi_driver(dev->driver); - int err = -ENODEV; + struct exi_map_id_to_name *map = exi_map_id_to_name; - if (drv->probe) - err = drv->probe(exi_dev); + while(map->id) { + if (map->id == id) + return map->name; + map++; + } + return "Unknown"; +} - return err; + +/* + * Internal. Check if an exi device matches a given exi device id. + */ +static int exi_device_match_one(const struct exi_device_id *eid, + const struct exi_device *exi_device) +{ + /* + * We allow drivers to claim devices that do not provide + * EXI identifiers by matching directly on channel/device. + * These drivers must use EXI_ID_NONE on their eids. + */ + if (eid->id == exi_device->eid.id || eid->id == EXI_ID_NONE) { + /* match against channel and device */ + if (exi_device->eid.channel == eid->channel && + exi_device->eid.device == eid->device) { + return 1; + } + } + return 0; } -static int exi_device_remove(struct device *dev) +/* + * Internal. Check if an exi device matches a given set of exi device ids. + * Return the exi device identifier or %NULL if there is no match. + */ +static const struct exi_device_id * +exi_device_match(const struct exi_device_id *eids, + const struct exi_device *exi_device) { - struct exi_dev *exi_dev = to_exi_dev(dev); - struct exi_driver *drv = to_exi_driver(dev->driver); + while (eids && eids->id) { + if (exi_device_match_one(eids, exi_device)) + return eids; + eids++; + } + return NULL; +} - if (drv->remove) - drv->remove(exi_dev); +/* + * Internal. Used to check if an exi device is supported by an exi driver. + */ +static int exi_bus_match(struct device *dev, struct device_driver *drv) +{ + struct exi_device *exi_device = to_exi_device(dev); + struct exi_driver *exi_driver = to_exi_driver(drv); + const struct exi_device_id *eids = exi_driver->eid_table; + if (eids && exi_device_match(eids, exi_device)) + return 1; return 0; } + +/* + * Internal. Initialize an exi_device structure. + */ +static void exi_device_init(struct exi_device *exi_device, + unsigned int channel, unsigned int device) +{ + memset(exi_device, 0, sizeof(*exi_device)); + + exi_device->eid.id = EXI_ID_INVALID; + exi_device->eid.channel = channel; + exi_device->eid.device = device; + exi_device->frequency = -1; + + exi_device->exi_channel = to_exi_channel(channel); + + device_initialize(&exi_device->dev); + exi_device->dev.parent = &exi_bus_devices[channel]; + exi_device->dev.bus = &exi_bus_type; + exi_device->dev.platform_data = to_exi_channel(channel); + + sprintf(exi_device->dev.bus_id, "%01x:%01x", channel, device); +} + /** - * exi_driver_register - register an EXI device driver. - * @drv: driver structure to register. + * exi_device_get - Increments the reference count of the exi device + * @exi_device: device being referenced * - * Registers an EXI device driver with the bus - * and consequently with the driver model core. + * Each live reference to an exi device should be refcounted. + * A pointer to the device with the incremented reference counter + * is returned. */ -int exi_driver_register(struct exi_driver *drv) +struct exi_device *exi_device_get(struct exi_device *exi_device) { - drv->driver.name = drv->name; - drv->driver.bus = &exi_bus_type; - drv->driver.probe = exi_device_probe; - drv->driver.remove = exi_device_remove; + if (exi_device) + get_device(&exi_device->dev); + return exi_device; +} - return driver_register(&drv->driver); +/** + * exi_device_put - Releases a use of the exi device + * @exi_device: device that's been disconnected + * + * Must be called when a user of a device is finished with it. + */ +void exi_device_put(struct exi_device *exi_device) +{ + if (exi_device) + put_device(&exi_device->dev); +} + +/** + * exi_get_exi_device - Returns a reference to an exi device + * @exi_channel: exi channel where the device is located + * @device: device number within the channel + */ +struct exi_device *exi_get_exi_device(struct exi_channel *exi_channel, + int device) +{ + return &exi_devices[to_channel(exi_channel)][device]; +} + +/* + * Internal. Call device driver probe function on match. + */ +static int exi_device_probe(struct device *dev) +{ + struct exi_device *exi_device = to_exi_device(dev); + struct exi_driver *exi_driver = to_exi_driver(dev->driver); + const struct exi_device_id *eid; + int retval = -ENODEV; + + if (!exi_driver->eid_table) + goto out; + + eid = exi_device_match(exi_driver->eid_table, exi_device); + if (eid) { + exi_device->frequency = exi_driver->frequency; + if (exi_driver->probe) + retval = exi_driver->probe(exi_device); + } + if (retval >= 0) { + retval = 0; + } + +out: + return retval; +} + +/* + * Internal. Call device driver remove function. + */ +static int exi_device_remove(struct device *dev) +{ + struct exi_device *exi_device = to_exi_device(dev); + struct exi_driver *exi_driver = to_exi_driver(dev->driver); + + if (exi_driver->remove) + exi_driver->remove(exi_device); + + return 0; } -EXPORT_SYMBOL(exi_driver_register); /** - * exi_driver_unregister - unregister an EXI device driver. - * @drv: driver structure to unregister. + * exi_driver_register - register an EXI device driver. + * @driver: driver structure to register. * - * Unregisters an EXI device driver with the bus - * and consequently with the driver model core. + * Registers an EXI device driver with the bus + * and consequently with the driver model core. */ -void exi_driver_unregister(struct exi_driver *drv) +int exi_driver_register(struct exi_driver *driver) { - driver_unregister(&drv->driver); + driver->driver.name = driver->name; + driver->driver.bus = &exi_bus_type; + driver->driver.probe = exi_device_probe; + driver->driver.remove = exi_device_remove; + + return driver_register(&driver->driver); } -EXPORT_SYMBOL(exi_driver_unregister); +/** + * exi_driver_unregister - unregister an EXI device driver. + * @driver: driver structure to unregister. + * + * Unregisters an EXI device driver with the bus + * and consequently with the driver model core. + */ +void exi_driver_unregister(struct exi_driver *driver) +{ + driver_unregister(&driver->driver); +} -static int exi_bus_match(struct device *dev, struct device_driver *drv) +/* + * Internal. Re-scan a given exi channel, looking for added, changed and + * removed exi devices. + * XXX Currently, only _new_ devices are taken into account. + */ +static void exi_channel_rescan(struct exi_channel *exi_channel) { - struct exi_dev *exi_dev = to_exi_dev(dev); - struct exi_driver *exi_drv = to_exi_driver(drv); - const struct exi_device_id *ids = exi_drv->id_table; + struct exi_device *exi_device; + unsigned int channel, device, id; - if (!ids) - return 0; + spin_lock(&exi_channel->lock); - while (ids->dev_id) { - if (ids->dev_id == exi_dev->id) - return 1; - ids++; + /* add the exi devices underneath the parents */ + for (device = 0; device < EXI_DEVICES_PER_CHANNEL; ++device) { + channel = to_channel(exi_channel); + exi_device = &exi_devices[channel][device]; + + /* now ID the device */ + id = exi_get_id(exi_channel, device, EXI_FREQ_SCAN); + + /* + * We only process currently _new_ devices here. + */ + if (id != EXI_ID_INVALID) { + exi_printk(KERN_INFO, "[%s] id=0x%08x %s\n", + exi_device->dev.bus_id, + id, exi_name_id(id)); + + if (exi_device->eid.id == EXI_ID_INVALID) { + /* a new device has been found */ + exi_device->eid.id = id; + device_register(&exi_device->dev); + } else { + /* device changed */ + /* remove, add */ + } + } else { + if (exi_device->eid.id != EXI_ID_INVALID) { + /* device removed */ + /* remove */ + } + } } - return 0; + spin_unlock(&exi_channel->lock); } -struct bus_type exi_bus_type = { - .name = "exi", - .match = exi_bus_match, -}; +/* + * Internal. Scans all the exi channels looking for exi devices. + */ +static void exi_bus_rescan(void) +{ + struct exi_channel *exi_channel; + unsigned int channel; -EXPORT_SYMBOL(exi_bus_type); + for (channel = 0; channel < EXI_MAX_CHANNELS; ++channel) { + exi_channel = to_exi_channel(channel); + exi_channel_rescan(exi_channel); + } +} -struct device exi_bus_dev = { - .bus_id = "exi0", + +static struct exi_device exi_devices[EXI_MAX_CHANNELS][EXI_DEVICES_PER_CHANNEL]; + +static struct bus_type exi_bus_type = { + .name = "exi", + .match = exi_bus_match, }; -EXPORT_SYMBOL(exi_bus_dev); +static struct device exi_bus_devices[EXI_MAX_CHANNELS] = { + [0] = {.bus_id = "exi0"}, + [1] = {.bus_id = "exi1"}, + [2] = {.bus_id = "exi2"}, +}; -static int __init exi_driver_init(void) +extern void exi_channel_init(struct exi_channel *exi_channel, + unsigned int channel); + +static int __init exi_layer_init(void) { - int err; + struct exi_channel *exi_channel; + struct exi_device *exi_device; + unsigned int channel, device; + int retval; - if ((err = device_register(&exi_bus_dev))) - goto out; - if ((err = bus_register(&exi_bus_type))) - goto out; -out: - return err; + exi_printk(KERN_INFO, "%s - version %s\n", DRV_DESCRIPTION, + exi_driver_version); + + extern unsigned long exi_running; + if (!test_and_set_bit(1, &exi_running)) { + retval = exi_hw_init(); + if (retval) + goto err_irq_init; + } + + /* initialize channels and devices */ + for (channel = 0; channel < EXI_MAX_CHANNELS; ++channel) { + exi_channel = to_exi_channel(channel); + exi_channel_init(exi_channel, channel); + for (device = 0; device < EXI_DEVICES_PER_CHANNEL; ++device) { + exi_device = &exi_devices[channel][device]; + exi_device_init(exi_device, channel, device); + } + } + + /* register root devices */ + for (channel = 0; channel < EXI_MAX_CHANNELS; ++channel) { + retval = device_register(&exi_bus_devices[channel]); + if (retval) + goto err_device_register; + } + + /* register the bus */ + retval = bus_register(&exi_bus_type); + if (retval) + goto err_bus_register; + + /* now enumerate through the bus and add all detected devices */ + exi_bus_rescan(); + + return 0; + +err_bus_register: +err_device_register: + while(--channel > 0) { + device_unregister(&exi_bus_devices[channel]); + } + exi_hw_exit(); +err_irq_init: + return retval; } -postcore_initcall(exi_driver_init); +EXPORT_SYMBOL(exi_driver_register); +EXPORT_SYMBOL(exi_driver_unregister); +EXPORT_SYMBOL(exi_bus_type); + +EXPORT_SYMBOL(exi_get_exi_device); +EXPORT_SYMBOL(exi_device_get); +EXPORT_SYMBOL(exi_device_put); + + +postcore_initcall(exi_layer_init); + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_LICENSE("GPL"); + Index: exi-hw.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/exi/exi-hw.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- exi-hw.c 13 Jan 2005 01:55:32 -0000 1.2 +++ exi-hw.c 13 Mar 2005 21:49:16 -0000 1.3 @@ -1,9 +1,10 @@ /* * drivers/exi/exi-hw.c * - * Nintendo GameCube EXI driver + * Nintendo GameCube EXpansion Interface support. Hardware routines. * Copyright (C) 2004-2005 The GameCube Linux Team * Copyright (C) 2004,2005 Todd Jeffreys <to...@vo...> + * Copyright (C) 2005 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License [...1382 lines suppressed...] + exi_quiesce_all_channels(0); + free_irq(EXI_IRQ, NULL); +} + + +EXPORT_SYMBOL(to_exi_channel); + +EXPORT_SYMBOL(exi_select_raw); +EXPORT_SYMBOL(exi_deselect_raw); +EXPORT_SYMBOL(exi_transfer_raw); +EXPORT_SYMBOL(exi_dma_transfer_raw); + +EXPORT_SYMBOL(exi_select); +EXPORT_SYMBOL(exi_deselect); +EXPORT_SYMBOL(exi_transfer); + +EXPORT_SYMBOL(exi_get_id); +EXPORT_SYMBOL(exi_event_register); +EXPORT_SYMBOL(exi_event_unregister); + --- exi-bus.c DELETED --- --- exi_priv.h DELETED --- --- gcn-exi-lite-tmbinc-exi_c.c DELETED --- --- gcn-exi-lite.c DELETED --- --- gcn-exi-lite.h DELETED --- |
From: <he...@us...> - 2005-03-13 21:49:26
|
Update of /cvsroot/gc-linux/linux/include/linux In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4397/include/linux Modified Files: exi.h Log Message: Added yet another EXI Layer Framework. Index: exi.h =================================================================== RCS file: /cvsroot/gc-linux/linux/include/linux/exi.h,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- exi.h 13 Jan 2005 01:55:32 -0000 1.8 +++ exi.h 13 Mar 2005 21:49:15 -0000 1.9 @@ -1,9 +1,11 @@ /* * include/linux/exi.h * - * Nintendo GameCube EXI driver + * Nintendo GameCube EXpansion Interface definitions * Copyright (C) 2004-2005 The GameCube Linux Team + * Copyright (C) 2004 Arthur Othieno <a.o...@bl...> * Copyright (C) 2004,2005 Todd Jeffreys <to...@vo...> + * Copyright (C) 2005 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,97 +14,326 @@ * */ -#ifndef __exi_bus__ -#define __exi_bus__ +#ifndef __EXI_H +#define __EXI_H -#define EXI_DMA_ALIGNMENT 32 -/* ------------------- - exi_sub_command flags - ----------------- */ -#define EXI_CMD_READ (0x00000000) -#define EXI_CMD_WRITE (0x00000005) +#include <linux/device.h> +#include <asm/io.h> -#define EXI_INVALID_ID 0xFFFFFFFF +extern struct bus_type exi_bus_type; +struct exi_channel; -/* ---------------------- - exi_command flags - --------------------- */ +/* + * + */ +struct exi_device_id { + unsigned int channel; +#define EXI_CHANNEL_ANY (~0) -#define EXI_DESELECT_UDELAY (0x00000001) + unsigned int device; +#define EXI_DEVICE_ANY (~0) + + u32 id; +#define EXI_ID_INVALID (~0) +#define EXI_ID_NONE (EXI_ID_INVALID-1) +}; -#include <linux/device.h> -#include <linux/list.h> +/* + * + */ +struct exi_device { + struct exi_channel *exi_channel; -struct exi_command -{ - unsigned int flags; - - void *data; - unsigned int len; - - void *param; - void (*completion_routine)(struct exi_command *cmd); + struct exi_device_id eid; + int frequency; + + unsigned long flags; + + struct device dev; }; -struct exi_command_group -{ - struct list_head list; - - struct exi_device *dev; - - unsigned int flags; - - unsigned int deselect_udelay; +#define to_exi_device(n) container_of(n,struct exi_device,dev) + +struct exi_device *exi_get_exi_device(struct exi_channel *exi_channel, + int device); + +/* + * + */ +struct exi_driver { + char *name; + struct exi_device_id *eid_table; + int frequency; - unsigned int num_commands; - struct exi_command *commands; + int (*probe) (struct exi_device *dev); + void (*remove) (struct exi_device *dev); + + struct device_driver driver; }; -extern struct bus_type exi_bus_type; +#define to_exi_driver(n) container_of(n,struct exi_driver,driver) -struct exi_device_id + +/* + * EXpansion Interface devices and drivers. + * + */ +extern struct exi_device *exi_device_get(struct exi_device *exi_device); +extern void exi_device_put(struct exi_device *exi_device); + +extern int exi_driver_register(struct exi_driver *exi_driver); +extern void exi_driver_unregister(struct exi_driver *exi_driver); + +static inline void *exi_get_drvdata(struct exi_device *exi_dev) { - unsigned int channel; - unsigned int device; - - u32 id; -}; + return dev_get_drvdata(&exi_dev->dev); +} + +static inline void exi_set_drvdata(struct exi_device *exi_dev, void *data) +{ + dev_set_drvdata(&exi_dev->dev, data); +} -struct exi_device + +/* + * EXpansion Interface channels. + * + */ + +extern struct exi_channel *to_exi_channel(unsigned int channel); +extern unsigned int to_channel(struct exi_channel *exi_channel); + +static inline struct exi_channel *exi_get_exi_channel(struct exi_device *dev) { - struct exi_device_id eid; + return dev->exi_channel; +} - struct device dev; +#define EXI_EVENT_IRQ 0 +#define EXI_EVENT_INSERT 1 +#define EXI_EVENT_TC 2 + +typedef int (*exi_event_handler_t)(struct exi_channel *exi_channel, + unsigned int event_id, void *data); + +extern int exi_event_register(struct exi_channel *exi_channel, + unsigned int event_id, + exi_event_handler_t handler, void *data, + unsigned int channel_mask); +extern int exi_event_unregister(struct exi_channel *exi_channel, + unsigned int event_id); + + +/* + * Commands. + * + * + */ +struct exi_command { + int opcode; +#define EXI_OP_READ (0x00<<2) /* same as in EXIxCR */ +#define EXI_OP_WRITE (0x01<<2) /* same as in EXIxCR */ +#define EXI_OP_READWRITE (0x02<<2) /* same as in EXIxCR */ + +#define EXI_OP_SELECT 0x0100 +#define EXI_OP_DESELECT 0x0200 +#define EXI_OP_NOP -1 + + unsigned long flags; +#define EXI_NODMA (1<<0) + + void *data; + size_t len; + + dma_addr_t dma_addr; + size_t dma_len; + + void *done_data; + void (*done)(struct exi_command *cmd); + + struct exi_channel *exi_channel; }; -#define to_exi_device(n) container_of(n,struct exi_device,dev) +static inline void exi_op_basic(struct exi_command *cmd, + struct exi_channel *exi_channel) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->exi_channel = exi_channel; +} -struct exi_driver +static inline void exi_op_nop(struct exi_command *cmd, + struct exi_channel *exi_channel) { - char *name; - struct exi_device_id eid; - unsigned int frequency; - - int (*probe) (struct exi_device *dev); - void (*remove) (struct exi_device *dev); + exi_op_basic(cmd, exi_channel); + cmd->opcode = EXI_OP_NOP; +} - struct device_driver driver; -}; +static inline void exi_op_select(struct exi_command *cmd, + struct exi_device *exi_device) +{ + exi_op_basic(cmd, exi_device->exi_channel); + cmd->opcode = EXI_OP_SELECT; + cmd->data = exi_device; +} -typedef int (*exi_irq_handler)(int channel,void *param); +static inline void exi_op_deselect(struct exi_command *cmd, + struct exi_channel *exi_channel) +{ + exi_op_basic(cmd, exi_channel); + cmd->opcode = EXI_OP_DESELECT; +} -#define to_exi_driver(n) container_of(n,struct exi_driver,driver) +static inline void exi_op_transfer(struct exi_command *cmd, + struct exi_channel *exi_channel, + void *data, size_t len, int opcode) +{ + exi_op_basic(cmd, exi_channel); + cmd->opcode = opcode; + cmd->data = data; + cmd->len = len; +} -void exi_add_command_group(struct exi_command_group *cmd,unsigned int count); +static inline void exi_op_read(struct exi_command *cmd, + struct exi_channel *exi_channel, + void *data, size_t len) +{ + exi_op_transfer(cmd, exi_channel, data, len, EXI_OP_READ); +} -int exi_register_driver(struct exi_driver *drv); -void exi_unregister_driver(struct exi_driver *drv); +static inline void exi_op_write(struct exi_command *cmd, + struct exi_channel *exi_channel, + void *data, size_t len) +{ + exi_op_transfer(cmd, exi_channel, data, len, EXI_OP_WRITE); +} -int exi_register_irq(int channel_irq,exi_irq_handler func,void *param); -void exi_unregister_irq(int channel_irq); -#define exi_get_driver_data(exi_device) dev_get_drvdata(&exi_device->dev) -#define exi_set_driver_data(exi_device,data) dev_set_drvdata(&exi_device->dev,data) +/* + * EXpansion Interface interfaces. + * + */ +#include "../drivers/exi/exi-hw.h" + +/* + * Raw. + */ +extern void exi_select_raw(struct exi_channel *exi_channel, + unsigned int device, unsigned int freq); +extern void exi_deselect_raw(struct exi_channel *exi_channel); + +#define exi_transfer_u8_raw __exi_transfer_raw_u8 +#define exi_transfer_u16_raw __exi_transfer_raw_u16 +#define exi_transfer_u32_raw __exi_transfer_raw_u32 + +extern void exi_transfer_raw(struct exi_channel *exi_channel, + void *data, size_t len, int mode); +extern void exi_dma_transfer_raw(struct exi_channel *channel, + dma_addr_t data, size_t len, int mode); + +/* + * Standard. + */ + +extern u32 exi_get_id(struct exi_channel *exi_channel, + unsigned int device, unsigned int freq); + +void exi_select(struct exi_device *exi_device); +void exi_deselect(struct exi_channel *exi_channel); +void exi_transfer(struct exi_channel *exi_channel, + void *data, size_t len, int opcode); + +#define exi_dev_select(d) exi_select(d) + +static inline void exi_dev_deselect(struct exi_device *exi_device) +{ + return exi_deselect(exi_device->exi_channel); +} + +static inline void exi_dev_transfer(struct exi_device *exi_device, + void *data, size_t len, int opcode) +{ + return exi_transfer(exi_device->exi_channel, data, len, opcode); +} + +static inline void exi_dev_read(struct exi_device *dev, void *data, size_t len) +{ + exi_dev_transfer(dev, data, len, EXI_OP_READ); +} + +static inline void exi_dev_write(struct exi_device *dev, void *data, size_t len) +{ + exi_dev_transfer(dev, data, len, EXI_OP_WRITE); +} + + + +/* + * Compatibility layer with old EXI_LITE. + */ + +#ifdef CONFIG_EXI_LITE2_COMPAT + +#ifndef EXI_LITE +#define EXI_LITE 2 + +extern unsigned long exi_running; + +static inline int exi_lite_init(void) +{ + int retval = 0; + + if (!test_and_set_bit(1, &exi_running)) { + retval = exi_hw_init(); + } + return retval; +} + +static inline void exi_lite_exit(void) +{ + exi_hw_exit(); +} + +static inline void exi_lite_select(int channel, int device, int freq) +{ + struct exi_channel *exi_channel = to_exi_channel(channel); + struct exi_device *exi_device = exi_get_exi_device(exi_channel, device); + exi_select(exi_device); +} + +static inline void exi_lite_deselect(int channel) +{ + struct exi_channel *exi_channel = to_exi_channel(channel); + exi_deselect(exi_channel); +} + +static inline void exi_lite_read(int channel, void *data, size_t len) +{ + exi_transfer(to_exi_channel(channel), data, len, EXI_OP_READ); +} + +static inline void exi_lite_write(int channel, void *data, size_t len) +{ + exi_transfer(to_exi_channel(channel), data, len, EXI_OP_WRITE); +} + +static inline int exi_lite_register_event(int channel, int event_id, + exi_event_handler_t handler, + void *dev, unsigned int channel_mask) +{ + return exi_event_register(to_exi_channel(channel), + (unsigned int)event_id, + handler, dev, channel_mask); +} + +static inline int exi_lite_unregister_event(int channel, int event_id) +{ + return exi_event_unregister(to_exi_channel(channel), + (unsigned int)event_id); +} + +#endif /* EXI_LITE */ + +#endif /* CONFIG_EXI_LITE2_COMPAT */ + +#endif /* __EXI_H */ -#endif |