You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
(12) |
May
(82) |
Jun
(72) |
Jul
(39) |
Aug
(104) |
Sep
(61) |
Oct
(55) |
Nov
(101) |
Dec
(48) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(52) |
Feb
(67) |
Mar
(18) |
Apr
(16) |
May
(33) |
Jun
(12) |
Jul
(102) |
Aug
(168) |
Sep
(65) |
Oct
(60) |
Nov
(43) |
Dec
(121) |
2002 |
Jan
(69) |
Feb
(32) |
Mar
(90) |
Apr
(59) |
May
(45) |
Jun
(43) |
Jul
(33) |
Aug
(21) |
Sep
(11) |
Oct
(20) |
Nov
(26) |
Dec
(3) |
2003 |
Jan
(12) |
Feb
(18) |
Mar
(11) |
Apr
(11) |
May
(41) |
Jun
(76) |
Jul
(77) |
Aug
(15) |
Sep
(38) |
Oct
(56) |
Nov
(19) |
Dec
(39) |
2004 |
Jan
(17) |
Feb
(52) |
Mar
(36) |
Apr
(34) |
May
(48) |
Jun
(85) |
Jul
(38) |
Aug
(42) |
Sep
(41) |
Oct
(77) |
Nov
(27) |
Dec
(19) |
2005 |
Jan
(32) |
Feb
(35) |
Mar
(29) |
Apr
(8) |
May
(7) |
Jun
(31) |
Jul
(46) |
Aug
(93) |
Sep
(65) |
Oct
(85) |
Nov
(219) |
Dec
(47) |
2006 |
Jan
(170) |
Feb
(103) |
Mar
(49) |
Apr
(43) |
May
(45) |
Jun
(29) |
Jul
(77) |
Aug
(82) |
Sep
(43) |
Oct
(45) |
Nov
(26) |
Dec
(85) |
2007 |
Jan
(42) |
Feb
(48) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(53) |
Jul
(175) |
Aug
(212) |
Sep
(91) |
Oct
(103) |
Nov
(110) |
Dec
(5) |
2008 |
Jan
(20) |
Feb
(11) |
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(5) |
Sep
(3) |
Oct
(12) |
Nov
|
Dec
|
From: Adrian M. <ad...@ne...> - 2007-09-22 21:32:31
|
On Sat, 2007-09-22 at 14:16 +0100, Adrian McMenamin wrote: > The code for PVR2 DMA in the kernel is currently completely broken at > both hardware handling and algorithmic levels and more than likely to > cash a fatal crash if used. > > This patch fixes the code and it seems to work well. I know it is not up > to the standards required to go to mainline yet, but any commentary on > it would be helpful. What I now realise is that this is not transferring a bit map, but a series of instructions to the tile accelerator. You can make it work like a bitmap, but that will also require more work... |
From: Adrian M. <ad...@ne...> - 2007-09-22 13:17:19
|
The code for PVR2 DMA in the kernel is currently completely broken at both hardware handling and algorithmic levels and more than likely to cash a fatal crash if used. This patch fixes the code and it seems to work well. I know it is not up to the standards required to go to mainline yet, but any commentary on it would be helpful. Signed-off by Adrian McMenamin <ad...@mc...> --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -18,23 +18,14 @@ #include <asm/dma.h> #include <asm/io.h> -static unsigned int xfer_complete; -static int count; - static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) { - if (get_dma_residue(PVR2_CASCADE_CHAN)) { - printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " - "on channel %d, waiting..\n", PVR2_CASCADE_CHAN); - dma_wait_for_completion(PVR2_CASCADE_CHAN); + struct dma_channel *channel; + if (likely(!get_dma_residue(PVR2_CASCADE_CHAN))) { + channel = get_dma_channel(PVR2_CASCADE_CHAN); + wake_up(&channel->wait_queue); } - if (count++ < 10) - pr_debug("Got a pvr2 dma interrupt for channel %d\n", - irq - HW_EVENT_PVR2_DMA); - - xfer_complete = 1; - return IRQ_HANDLED; } @@ -42,15 +33,12 @@ static int pvr2_request_dma(struct dma_channel *chan) { if (ctrl_inl(PVR2_DMA_MODE) != 0) return -EBUSY; - - ctrl_outl(0, PVR2_DMA_LMMODE0); - return 0; } static int pvr2_get_dma_residue(struct dma_channel *chan) { - return xfer_complete == 0; + return ctrl_inl(PVR2_DMA_MODE); } static int pvr2_xfer_dma(struct dma_channel *chan) @@ -58,11 +46,9 @@ static int pvr2_xfer_dma(struct dma_channel *chan) if (chan->sar || !chan->dar) return -EINVAL; - xfer_complete = 0; - ctrl_outl(chan->dar, PVR2_DMA_ADDR); ctrl_outl(chan->count, PVR2_DMA_COUNT); - ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); + ctrl_outl(1, PVR2_DMA_MODE); return 0; } --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -677,11 +677,14 @@ static int pvr2_init_cable(void) static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, size_t count, loff_t *ppos) { - unsigned long dst, start, end, len; + unsigned long dst, start, end, len, phys_dst; unsigned int nr_pages; struct page **pages; int ret, i; + /* Bounds check */ + if (*ppos > 0x2FFFFF) return -ENOSPC; + nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT; pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); @@ -698,39 +701,57 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, ret = -EINVAL; goto out_unmap; } - - dma_configure_channel(shdma, 0x12c1); + dst = (unsigned long)fb_info->screen_base + *ppos; start = (unsigned long)page_address(pages[0]); - end = (unsigned long)page_address(pages[nr_pages]); + end = (unsigned long)page_address(pages[nr_pages - 1]); len = nr_pages << PAGE_SHIFT; + if ((*ppos + len) > 0x2FFFFF) + len = 0x2FFFFF - *ppos; + + /* transfer is via Tile Accelerator */ + phys_dst = PHYSADDR(*ppos + 0x11000000); + if (phys_dst >= 0x11000000 && phys_dst <= 0x11FFFFE0){ + ctrl_outl(0, PVR2_DMA_LMMODE0); + ctrl_outl(1, PVR2_DMA_LMMODE1); + } + else if (phys_dst >= 0x13000000 && phys_dst <= 0x13FFFFE0) { + ctrl_outl(1, PVR2_DMA_LMMODE0); + ctrl_outl(0, PVR2_DMA_LMMODE1); + } + else { + ctrl_outl(1, PVR2_DMA_LMMODE0); + ctrl_outl(1, PVR2_DMA_LMMODE1); + } - /* Half-assed contig check */ - if (start + len == end) { - /* As we do this in one shot, it's either all or nothing.. */ - if ((*ppos + len) > fb_info->fix.smem_len) { - ret = -ENOSPC; - goto out_unmap; - } - - dma_write(shdma, start, 0, len); - dma_write(pvr2dma, 0, dst, len); - dma_wait_for_completion(pvr2dma); + if (start + len == end + (1 << PAGE_SHIFT)) { + ctrl_outl(0, PVR2_DMA_MODE); /* DMA off for now */ + ctrl_outl(0x12c0, 0xFFA0002C); /* set transfer flags to off */ + ctrl_outl(start, 0xFFA00020); /* set channel 2 start address */ + ctrl_outl(len/32, 0xFFA00028); /* chan2 dma is in 32 byte lumps */ + ctrl_outl(0x12c1, 0xFFA0002C); /* set flags to be ready to go */ + ctrl_outl(phys_dst, PVR2_DMA_ADDR); /* transfer is via the TA */ + ctrl_outl(len, PVR2_DMA_COUNT); + ctrl_outl(1, PVR2_DMA_MODE); /* and go... */ + dma_wait_for_completion(shdma); /* sleep till we are done */ goto out; } /* Not contiguous, writeout per-page instead.. */ for (i = 0; i < nr_pages; i++, dst += PAGE_SIZE) { - if ((*ppos + (i << PAGE_SHIFT)) > fb_info->fix.smem_len) { - ret = -ENOSPC; - goto out_unmap; - } - - dma_write_page(shdma, (unsigned long)page_address(pages[i]), 0); - dma_write_page(pvr2dma, 0, dst); - dma_wait_for_completion(pvr2dma); + if ((*ppos + (1 << PAGE_SHIFT)) > 0x2FFFFF) + break; + ctrl_outl(0, PVR2_DMA_MODE); + ctrl_outl(0x12c0, 0xFFA0002C); + ctrl_outl((unsigned long)page_address(pages[i]), 0xFFA00020); + ctrl_outl(len/32, 0xFFA00028); + ctrl_outl(0x12c1, 0xFFA0002C); + ctrl_outl(phys_dst, PVR2_DMA_ADDR); + ctrl_outl(1 << PAGE_SHIFT, PVR2_DMA_COUNT); + ctrl_outl(1, PVR2_DMA_MODE); + dma_wait_for_completion(shdma); } out: @@ -890,7 +911,7 @@ static int __init pvr2fb_dc_init(void) pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */ pvr2_fix.mmio_len = 0x2000; - if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED, "pvr2 VBL handler", fb_info)) { return -EBUSY; } |
From: Paul M. <le...@li...> - 2007-09-22 07:56:24
|
On Sat, Sep 22, 2007 at 12:05:45PM +0900, shinkoi2005 wrote: > I want to use the latest Paul's git repository behind a proxy server. > So I have been using > http://www.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git > instead of > git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git > > But http's repository version is still 2.6.23-rc1... > What should I do? > It should be fixed now, there hadn't been a git-update-server-info run in some time. Normally I have the post-update script take care of that, but the permissions were cleared when I shuffled the directories around. Try it again and let me know if you have any problems. |
From: shinkoi2005 <shi...@gm...> - 2007-09-22 03:05:51
|
Hi all. I want to use the latest Paul's git repository behind a proxy server. So I have been using http://www.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git instead of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git But http's repository version is still 2.6.23-rc1... What should I do? |
From: Adrian M. <ad...@ne...> - 2007-09-21 07:19:31
|
On Fri, 2007-09-21 at 16:00 +0900, Paul Mundt wrote: > On Thu, Sep 20, 2007 at 12:29:40PM +0100, Adrian McMenamin wrote: > > The Maple bus is SEGA's proprietary serial bus for peripherals > > (keyboard, mouse, controller etc). The bus is capable of some > > (limited) hotplugging and operates at up to 2 M/bits. > > > I've applied this and the header changes with a bit of tidying. Dmitry can > merge the keyboard driver in the input tree at any time, the Kconfig > dependency will just prevent it from showing up until the SH tree has > merged. > Thanks |
From: Paul M. <le...@li...> - 2007-09-21 07:01:27
|
On Thu, Sep 20, 2007 at 12:29:40PM +0100, Adrian McMenamin wrote: > The Maple bus is SEGA's proprietary serial bus for peripherals > (keyboard, mouse, controller etc). The bus is capable of some > (limited) hotplugging and operates at up to 2 M/bits. > I've applied this and the header changes with a bit of tidying. Dmitry can merge the keyboard driver in the input tree at any time, the Kconfig dependency will just prevent it from showing up until the SH tree has merged. |
From: Paul M. <pau...@re...> - 2007-09-21 06:25:18
|
On Mon, Sep 17, 2007 at 12:09:15PM +0200, Markus Brunner wrote: > this update moves the flash mapping for the Magic Panel into the board setup. > It also removes references to the old MTD mapping option in the defconfig. > > Signed-off by: Markus Brunner <sup...@gm...> > Signed-off by: Mark Jonas <to...@gm...> Applied, thanks. |
From: Paul M. <le...@li...> - 2007-09-21 06:07:52
|
On Sat, Sep 15, 2007 at 11:00:46AM +0900, shinkoi2005 wrote: > > Is the libata code working properly with 8 bit reads? Is this patch > > all it takes to get CF working on R2D-1? > > At least, cf_ide_resources[](register map) is also incorrect with R2D-PLUS. > Please check follow kernel which support P2D-PLUS and AT/PC arch's ATA register map. > <http://www.superh-linux.org/archive/bsp/sh7751r_r2d/linux-2.6.14.4-R2D+_20060906.tar.bz2> > R2D* board's ide register map is compatible without register access size. > > Here is the same patch... > I can boot R2D-1 from IDE's rootfs with this patch. > I suppose we can do this, I'll tidy up the patch a bit and apply it, thanks. It's probably worth doing the same thing for R7780RP, at least for the 2 or 3 people that have one of those antiquated things :-) |
From: Bernhard W. <bw...@su...> - 2007-09-20 17:18:53
|
This patch removes the crashkernel parsing from arch/sh/kernel/machine_kexec.c and calls the generic function, introduced in the generic patch, in setup_bootmem_allocator(). This is necessary because the amount of System RAM must be known in this function now because of the new syntax. NOTE: Due to the lack of a SH processor, this patch is untested (and uncompiled). Because the code in that area is quite similar as i386/x86_64 (contrary to PPC and IA64), it should compile and work. However, if someone of the SH people could test for me and provide feedback, that would be very nice. Signed-off-by: Bernhard Walle <bw...@su...> Acked-by: Paul Mundt <le...@li...> --- arch/sh/kernel/machine_kexec.c | 21 --------------------- arch/sh/kernel/setup.c | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 26 deletions(-) --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -104,24 +104,3 @@ NORET_TYPE void machine_kexec(struct kim (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); } -/* crashkernel=size@addr specifies the location to reserve for - * a crash kernel. By reserving this memory we guarantee - * that linux never sets it up as a DMA target. - * Useful for holding code to do something appropriate - * after a kernel panic. - */ -static int __init parse_crashkernel(char *arg) -{ - unsigned long size, base; - size = memparse(arg, &arg); - if (*arg == '@') { - base = memparse(arg+1, &arg); - /* FIXME: Do I want a sanity check - * to validate the memory range? - */ - crashk_res.start = base; - crashk_res.end = base + size - 1; - } - return 0; -} -early_param("crashkernel", parse_crashkernel); --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -121,6 +121,37 @@ static void __init register_bootmem_low_ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); } +#ifdef CONFIG_KEXEC +static void __init reserve_crashkernel(void) +{ + unsigned long long free_mem; + unsigned long long crash_size, crash_base; + int ret; + + free_mem = (max_low_pfn - min_low_pfn) << PAGE_SHIFT; + + ret = parse_crashkernel(boot_command_line, free_mem, + &crash_size, &crash_base); + if (ret == 0 && crash_size) { + if (crash_base > 0) { + printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " + "for crashkernel (System RAM: %ldMB)\n", + (unsigned long)(crash_size >> 20), + (unsigned long)(crash_base >> 20), + (unsigned long)(free_mem >> 20)); + crashk_res.start = crash_base; + crashk_res.end = crash_base + crash_size - 1; + reserve_bootmem(crash_base, crash_size); + } else + printk(KERN_INFO "crashkernel reservation failed - " + "you have to specify a base address\n"); + } +} +#else +static inline void __init reserve_crashkernel(void) +{} +#endif + void __init setup_bootmem_allocator(unsigned long free_pfn) { unsigned long bootmap_size; @@ -182,11 +213,8 @@ void __init setup_bootmem_allocator(unsi } } #endif -#ifdef CONFIG_KEXEC - if (crashk_res.start != crashk_res.end) - reserve_bootmem(crashk_res.start, - crashk_res.end - crashk_res.start + 1); -#endif + + reserve_crashkernel(); } #ifndef CONFIG_NEED_MULTIPLE_NODES -- |
From: Adrian M. <lkm...@gm...> - 2007-09-20 11:30:00
|
Add maplebus headers Signed off by Adrian McMenamin <ad...@mc...> diff --git a/include/linux/input.h b/include/linux/input.h diff --git a/include/linux/maple.h b/include/linux/maple.h new file mode 100644 index 0000000..e297cce --- /dev/null +++ b/include/linux/maple.h @@ -0,0 +1,87 @@ +/** + * maple.h + * + * porting to 2.6 driver model + * copyright Adrian McMenamin, 2007 + * + */ +#ifndef __LINUX_MAPLE_H +#define __LINUX_MAPLE_H + +extern struct bus_type maple_bus_type; + +/* Maple Bus command and response codes */ +enum maple_code { + MAPLE_RESPONSE_FILEERR = -5, + MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ + MAPLE_RESPONSE_BADCMD = -3, + MAPLE_RESPONSE_BADFUNC = -2, + MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ + MAPLE_COMMAND_DEVINFO = 1, + MAPLE_COMMAND_ALLINFO = 2, + MAPLE_COMMAND_RESET = 3, + MAPLE_COMMAND_KILL = 4, + MAPLE_RESPONSE_DEVINFO = 5, + MAPLE_RESPONSE_ALLINFO = 6, + MAPLE_RESPONSE_OK = 7, + MAPLE_RESPONSE_DATATRF = 8, + MAPLE_COMMAND_GETCOND = 9, + MAPLE_COMMAND_GETMINFO = 10, + MAPLE_COMMAND_BREAD = 11, + MAPLE_COMMAND_BWRITE = 12, + MAPLE_COMMAND_SETCOND = 14 +}; + +struct mapleq { + struct list_head list; + struct maple_device *dev; + void *sendbuf, *recvbuf, *recvbufdcsp; + unsigned char length; + enum maple_code command; +}; + +struct maple_devinfo { + unsigned long function; + unsigned long function_data[3]; + unsigned char area_code; + unsigned char connector_directon; + char product_name[31]; + char product_licence[61]; + unsigned short standby_power; + unsigned short max_power; +}; + +struct maple_device { + struct maple_driver *driver; + struct mapleq *mq; + void *private_data; + void (*callback) (struct mapleq * mq); + unsigned long when, interval, function; + struct maple_devinfo devinfo; + unsigned char port, unit; + char product_name[32]; + char product_licence[64]; + int registered; + struct device dev; +}; + +struct maple_driver { + unsigned long function; + int (*connect) (struct maple_device * dev); + void (*disconnect) (struct maple_device * dev); + struct device_driver drv; +}; + +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, + unsigned long function); + +int maple_driver_register(struct device_driver *drv); + +void maple_add_packet(struct mapleq *mq); + +#define to_maple_dev(n) container_of(n, struct maple_device, dev) +#define to_maple_driver(n) container_of(n, struct maple_driver, drv) + +#endif /* __LINUX_MAPLE_H */ diff --git a/include/asm-sh/dreamcast/maple.h b/include/asm-sh/dreamcast/maple.h new file mode 100644 index 0000000..4836d24 --- /dev/null +++ b/include/asm-sh/dreamcast/maple.h @@ -0,0 +1,36 @@ +#ifndef __ASM_MAPLE_H +#define __ASM_MAPLE_H + +#define MAPLE_PORTS 4 +#define MAPLE_PNP_INTERVAL HZ +#define MAPLE_MAXPACKETS 8 +#define MAPLE_DMA_ORDER 14 +#define MAPLE_DMA_SIZE (1 << MAPLE_DMA_ORDER) +#define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? MAPLE_DMA_ORDER - PAGE_SHIFT : 0) + +/* Maple Bus registers */ +#define MAPLE_BASE 0xa05f6c00 +#define MAPLE_DMAADDR (MAPLE_BASE+0x04) +#define MAPLE_TRIGTYPE (MAPLE_BASE+0x10) +#define MAPLE_ENABLE (MAPLE_BASE+0x14) +#define MAPLE_STATE (MAPLE_BASE+0x18) +#define MAPLE_SPEED (MAPLE_BASE+0x80) +#define MAPLE_RESET (MAPLE_BASE+0x8c) + +#define MAPLE_MAGIC 0x6155404f +#define MAPLE_2MBPS 0 +#define MAPLE_TIMEOUT(n) ((n)<<15) + +/* Function codes */ +#define MAPLE_FUNC_CONTROLLER 0x001 +#define MAPLE_FUNC_MEMCARD 0x002 +#define MAPLE_FUNC_LCD 0x004 +#define MAPLE_FUNC_CLOCK 0x008 +#define MAPLE_FUNC_MICROPHONE 0x010 +#define MAPLE_FUNC_ARGUN 0x020 +#define MAPLE_FUNC_KEYBOARD 0x040 +#define MAPLE_FUNC_LIGHTGUN 0x080 +#define MAPLE_FUNC_PURUPURU 0x100 +#define MAPLE_FUNC_MOUSE 0x200 + +#endif /* __ASM_MAPLE_H */ |
From: Adrian M. <lkm...@gm...> - 2007-09-20 11:29:56
|
This patch adds support for the keyboard on the SEGA Dreamcast Signed-off by Adrian McMenamin <ad...@mc...> Acked-by: Arjan van de Ven <ar...@li...> Acked-by: Dmitry Torokhov <dmi...@gm...> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c97d5eb..056cc52 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -253,4 +253,14 @@ config KEYBOARD_GPIO To compile this driver as a module, choose M here: the module will be called gpio-keys. + +config KEYBOARD_MAPLE + tristate "Maple bus keyboard" + depends on SH_DREAMCAST && MAPLE + help + Say Y here if you have a Dreamcast console running Linux and have + a keyboard attached to its Maple bus. + + To compile this driver as a module, choose M here: the + module will be called maple_keyb. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 28d211b..3f775ed 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o +obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 0000000..3bb58e1 --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c @@ -0,0 +1,234 @@ +/* + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + * Copyright YAEGASHI Takeshi, 2001 + * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/maple.h> +#include <asm/mach/maple.h> + +/* Very simple mutex to ensure proper cleanup */ +static DEFINE_MUTEX(maple_keyb_mutex); + +#define NR_SCANCODES 256 + +MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin"); +MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); +MODULE_LICENSE("GPL"); + +struct dc_kbd { + struct input_dev *dev; + unsigned char keycode[NR_SCANCODES]; + unsigned char new[8]; + unsigned char old[8]; +}; + +const static unsigned char dc_kbd_keycode[NR_SCANCODES] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D, + KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, + KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, + KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, + KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, + KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, + KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, + KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, + KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, + KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, + KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, + KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, + KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, + KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, + KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, + KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static void dc_scan_kbd(struct dc_kbd *kbd) +{ + int i; + void *ptr; + struct input_dev *dev = kbd->dev; + + for (i = 0; i < 8; i++) + input_report_key(dev, kbd->keycode[i + 224], + (kbd->new[0] >> i) & 1); + + for (i = 2; i < 8; i++) { + ptr = memchr(kbd->new + 2, kbd->old[i], 6); + if (kbd->old[i] > 3 && ptr == NULL) { + if (dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, kbd->keycode[kbd->old[i]], 0); + else + printk (KERN_DEBUG "Unknown key (scancode %#x) released.", kbd->old[i]); + } + ptr = memchr(kbd->old + 2, kbd->new[i], 6); + if (kbd->new[i] > 3 && ptr) { + if (dc_kbd_keycode[kbd->new[i]]) + input_report_key(dev, kbd->keycode[kbd->new[i]], 1); + else + printk(KERN_DEBUG "Unknown key (scancode %#x) pressed.", kbd->new[i]); + } + } + input_sync(dev); + memcpy(kbd->old, kbd->new, 8); +} + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = mapledev->private_data; + unsigned long *buf = mq->recvbuf; + + if (!mutex_trylock(&maple_keyb_mutex)) /* Can only be locked if already in cleanup */ + return; + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf + 2, 8); + dc_scan_kbd(kbd); + } + mutex_unlock(&maple_keyb_mutex); +} + +static int dc_kbd_connect(struct maple_device *mdev) +{ + int i, retval = 0; + struct dc_kbd *kbd; + struct input_dev *dev; + + if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) + return -EINVAL; + + kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + if (unlikely(!kbd)) + return -ENOMEM; + + mdev->private_data = kbd; + kbd->dev = input_allocate_device(); + if (!kbd->dev){ + retval = -ENODEV; + goto cleanup_memory; + } + + dev = kbd->dev; + + memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); + + dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + dev->keycodesize = sizeof (unsigned char); + dev->keycodemax = ARRAY_SIZE(kbd->keycode); + dev->keycode = kbd->keycode; + dev->dev.parent = &mdev->dev; + + for (i = 0; i < NR_SCANCODES; i++) + set_bit(dc_kbd_keycode[i], dev->keybit); + + clear_bit(0, dev->keybit); + + input_set_drvdata(dev, kbd); + + dev->name = mdev->product_name; + dev->id.bustype = BUS_HOST; + + retval = input_register_device(dev); + if (retval) + goto cleanup; + /* Maple polling is locked to VBLANK - which may be just 50/s */ + maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); + return retval; + +cleanup: + input_free_device(kbd->dev); +cleanup_memory: + kfree(kbd); + return retval; +} + +static void dc_kbd_disconnect(struct maple_device *mdev) +{ + struct dc_kbd *kbd; + + mutex_lock(&maple_keyb_mutex); + kbd = mdev->private_data; + + input_unregister_device(kbd->dev); + kfree(kbd); + mutex_unlock(&maple_keyb_mutex); +} + +/* allow the keyboard to be used */ +static int probe_maple_kbd(struct device *dev) +{ + struct maple_device *mdev; + struct maple_driver *mdrv; + int proberes; + + mdev = to_maple_dev(dev); + mdrv = to_maple_driver(dev->driver); + + proberes = dc_kbd_connect(mdev); + if (unlikely(proberes)) + return proberes; + mdev->driver = mdrv; + mdev->registered = 1; + return 0; +} + +static struct maple_driver dc_kbd_driver = { + .function = MAPLE_FUNC_KEYBOARD, + .connect = dc_kbd_connect, + .disconnect = dc_kbd_disconnect, + .drv = { + .name = "Dreamcast_keyboard", + .probe = probe_maple_kbd, + }, +}; + +static int __init dc_kbd_init(void) +{ + return maple_driver_register(&dc_kbd_driver.drv); +} + +static void __exit dc_kbd_exit(void) +{ + driver_unregister(&dc_kbd_driver.drv); +} + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); |
From: Adrian M. <lkm...@gm...> - 2007-09-20 11:29:53
|
This adds support for the maple bus (SEGA's proprietary serial bus on the Dreamcast) to the kernel. Signed-off by: Adrian McMenamin <ad...@mc...> diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 54878f0..077438f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -702,6 +702,17 @@ config CF_BASE_ADDR default "0xb8000000" if CF_AREA6 default "0xb4000000" if CF_AREA5 +config MAPLE + bool "Maple Bus Support" + depends on SH_DREAMCAST + help + The Maple Bus is SEGA's serial communication bus for peripherals + on the Dreamcast. Without this bus support you won't be able to + get your Dreamcast keyboard etc to work, so most users + probably want to say 'Y' here, unless you are only using the + Dreamcast with a serial line terminal or a remote network + connection. + source "arch/sh/drivers/pci/Kconfig" source "drivers/pci/Kconfig" diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 8a14389..f0a1f4f 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -3,4 +3,5 @@ # obj-$(CONFIG_SUPERHYWAY) += superhyway/ +obj-$(CONFIG_MAPLE) += maple/ diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile new file mode 100644 index 0000000..604ce33 --- /dev/null +++ b/drivers/sh/maple/Makefile @@ -0,0 +1,3 @@ +#Makefile for Maple Bus + +obj-$(CONFIG_MAPLE) := maplebus.o diff --git a/drivers/sh/maple/maplebus.c b/drivers/sh/maple/maplebus.c new file mode 100644 index 0000000..48eeee6 --- /dev/null +++ b/drivers/sh/maple/maplebus.c @@ -0,0 +1,731 @@ +/* maplebus.c + * Core maple bus functionality + * Original 2.4 code used here copyright + * YAEGASHI Takeshi, Paul Mundt, M. R. Brown and others + * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * + * Licensed under version 2 of the GPL + * See the COPYING file that came with this + * distribution for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/maple.h> +#include <linux/dma-mapping.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/mach/dma.h> +#include <asm/mach/sysasic.h> +#include <asm/mach/maple.h> + +MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, MR Brown, Adrian McMenamin"); +MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); + +static void maple_dma_handler(struct work_struct *work); +static void maple_vblank_handler(struct work_struct *work); + +static DECLARE_WORK(maple_dma_process, maple_dma_handler); +static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); + +static LIST_HEAD(maple_waitq); +static LIST_HEAD(maple_sentq); + +static DEFINE_MUTEX(maple_list_lock); + +static struct maple_driver maple_dummy_driver; +static struct device maple_bus; +static int subdevice_map[MAPLE_PORTS]; +static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; +static unsigned long maple_pnp_time; +static int started, scanning, liststatus; +static struct kmem_cache *maple_queue_cache; + +struct maple_device_specify { + int port; + int unit; +}; + +/** + * maple_driver_register - register a device driver + * automatically makes the driver bus a maple bus + * @drv: the driver to be registered + */ +int maple_driver_register(struct device_driver *drv) +{ + if (!drv) + return -EINVAL; + drv->bus = &maple_bus_type; + return driver_register(drv); +} + +EXPORT_SYMBOL_GPL(maple_driver_register); + +/* set hardware registers to enable next round of dma */ +static void maplebus_dma_reset(void) +{ + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ + ctrl_outl(1, MAPLE_TRIGTYPE); + ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); +} + +/** + * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND + * @dev: device responding + * @callback: handler callback + * @interval: interval in jiffies between callbacks + * @function: the function code for the device + */ +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, unsigned long function) +{ + dev->callback = callback; + dev->interval = interval; + dev->function = cpu_to_be32(function); + dev->when = jiffies; +} +EXPORT_SYMBOL_GPL(maple_getcond_callback); + +static int maple_dma_done(void) +{ + return (ctrl_inl(MAPLE_STATE) & 1) == 0; +} + +static void maple_release_device(struct device *dev) +{ + if (dev->type) { + kfree(dev->type->name); + kfree(dev->type); + } +} + +/** + * maple_add_packet - add a single instruction to the queue + * @mq: instruction to add to waiting queue + */ +void maple_add_packet(struct mapleq *mq) +{ + mutex_lock(&maple_list_lock); + list_add(&mq->list, &maple_waitq); + mutex_unlock(&maple_list_lock); +} +EXPORT_SYMBOL_GPL(maple_add_packet); + +static struct mapleq *maple_allocq(struct maple_device *dev) +{ + struct mapleq *mq; + + mq = kmalloc(sizeof(*mq), GFP_KERNEL); + if (!mq) + return NULL; + + mq->dev = dev; + mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); + mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); + if (!mq->recvbuf) { + kfree(mq); + return NULL; + } + + return mq; +} + +static struct maple_device *maple_alloc_dev(int port, int unit) +{ + struct maple_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->port = port; + dev->unit = unit; + dev->mq = maple_allocq(dev); + + if (!dev->mq) { + kfree(dev); + return NULL; + } + + return dev; +} + +static void maple_free_dev(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->mq) { + kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); + kfree(mdev->mq); + } + kfree(mdev); +} + +/* process the command queue into a maple command block + * terminating command has bit 32 of first long set to 0 + */ +static void maple_build_block(struct mapleq *mq) +{ + int port, unit, from, to, len; + unsigned long *lsendbuf = mq->sendbuf; + + port = mq->dev->port & 3; + unit = mq->dev->unit; + len = mq->length; + from = port << 6; + to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); + + *maple_lastptr &= 0x7fffffff; + maple_lastptr = maple_sendptr; + + *maple_sendptr++ = (port << 16) | len | 0x80000000; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = + mq->command | (to << 8) | (from << 16) | (len << 24); + + while (len-- > 0) + *maple_sendptr++ = *lsendbuf++; +} + +/* build up command queue */ +static void maple_send(void) +{ + int i; + int maple_packets; + struct mapleq *mq, *nmq; + + if (!list_empty(&maple_sentq)) + return; + if (list_empty(&maple_waitq) || !maple_dma_done()) + return; + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { + maple_build_block(mq); + list_move(&mq->list, &maple_sentq); + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + if (maple_packets > 0) { + for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) + dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, + PAGE_SIZE, DMA_BIDIRECTIONAL); + } +} + +static int attach_matching_maple_driver(struct device_driver *driver, + void *devptr) +{ + struct maple_driver *maple_drv; + struct maple_device *mdev; + + mdev = devptr; + maple_drv = to_maple_driver(driver); + if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { + if (maple_drv->connect(mdev) == 0) { + mdev->driver = maple_drv; + return 1; + } + } + return 0; +} + +static void maple_detach_driver(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->driver) { + if (mdev->driver->disconnect) + mdev->driver->disconnect(mdev); + } + mdev->driver = NULL; + if (mdev->registered) { + maple_release_device(&mdev->dev); + device_unregister(&mdev->dev); + } + mdev->registered = 0; + maple_free_dev(mdev); +} + +/* process initial MAPLE_COMMAND_DEVINFO for each device or port */ +static void maple_attach_driver(struct maple_device *dev) +{ + char *p; + + char *recvbuf; + unsigned long function; + int matched, retval; + + recvbuf = dev->mq->recvbuf; + memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); + memcpy(dev->product_name, dev->devinfo.product_name, 30); + memcpy(dev->product_licence, dev->devinfo.product_licence, 60); + dev->product_name[30] = '\0'; + dev->product_licence[60] = '\0'; + + for (p = dev->product_name + 29; dev->product_name <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + for (p = dev->product_licence + 59; dev->product_licence <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + function = be32_to_cpu(dev->devinfo.function); + + if (function > 0x200) { + /* Do this silently - as not a real device */ + function = 0; + dev->driver = &maple_dummy_driver; + sprintf(dev->dev.bus_id, "%d:0.port", dev->port); + } else { + printk(KERN_INFO + "Maple bus at (%d, %d): Connected function 0x%lX\n", + dev->port, dev->unit, function); + + matched = + bus_for_each_drv(&maple_bus_type, NULL, dev, + attach_matching_maple_driver); + + if (matched == 0) { + /* Driver does not exist yet */ + printk(KERN_INFO + "No maple driver found for this device\n"); + dev->driver = &maple_dummy_driver; + } + + sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, + dev->unit, function); + } + dev->function = function; + dev->dev.bus = &maple_bus_type; + dev->dev.parent = &maple_bus; + dev->dev.release = &maple_release_device; + retval = device_register(&dev->dev); + if (retval) { + printk(KERN_INFO + "Maple bus: Attempt to register device (%x, %x) failed.\n", + dev->port, dev->unit); + maple_free_dev(dev); + } + dev->registered = 1; +} + +/* if device has been registered for the given + * port and unit then return 1 - allows identification + * of which devices need to be attached or detached + */ +static int detach_maple_device(struct device *device, void *portptr) +{ + struct maple_device_specify *ds; + struct maple_device *mdev; + + ds = portptr; + mdev = to_maple_dev(device); + if (mdev->port == ds->port && mdev->unit == ds->unit) + return 1; + return 0; +} + +static int setup_maple_commands(struct device *device, void *ignored) +{ + struct maple_device *maple_dev = to_maple_dev(device); + + if ((maple_dev->interval > 0) + && time_after(jiffies, maple_dev->when)) { + maple_dev->when = jiffies + maple_dev->interval; + maple_dev->mq->command = MAPLE_COMMAND_GETCOND; + maple_dev->mq->sendbuf = &maple_dev->function; + maple_dev->mq->length = 1; + maple_add_packet(maple_dev->mq); + liststatus++; + } else { + if (time_after(jiffies, maple_pnp_time)) { + maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; + maple_dev->mq->length = 0; + maple_add_packet(maple_dev->mq); + liststatus++; + } + } + + return 0; +} + +/* VBLANK bottom half - implemented via workqueue */ +static void maple_vblank_handler(struct work_struct *work) +{ + if (!maple_dma_done()) + return; + if (!list_empty(&maple_sentq)) + return; + ctrl_outl(0, MAPLE_ENABLE); + liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, + setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) + maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; + if (liststatus && list_empty(&maple_sentq)) { + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + } + maplebus_dma_reset(); +} + +/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ +static void maple_map_subunits(struct maple_device *mdev, int submask) +{ + int retval, k, devcheck; + struct maple_device *mdev_add; + struct maple_device_specify ds; + + for (k = 0; k < 5; k++) { + ds.port = mdev->port; + ds.unit = k + 1; + retval = + bus_for_each_dev(&maple_bus_type, NULL, &ds, + detach_maple_device); + if (retval) { + submask = submask >> 1; + continue; + } + devcheck = submask & 0x01; + if (devcheck) { + mdev_add = maple_alloc_dev(mdev->port, k + 1); + if (!mdev_add) + return; + mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; + mdev_add->mq->length = 0; + maple_add_packet(mdev_add->mq); + scanning = 1; + } + submask = submask >> 1; + } +} + +/* mark a device as removed */ +static void maple_clean_submap(struct maple_device *mdev) +{ + int killbit; + + killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); + killbit = ~killbit; + killbit &= 0xFF; + subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; +} + +/* handle empty port or hotplug removal */ +static void maple_response_none(struct maple_device *mdev, + struct mapleq *mq) +{ + if (mdev->unit != 0) { + list_del(&mq->list); + maple_clean_submap(mdev); + printk(KERN_INFO + "Maple bus device detaching at (%d, %d)\n", + mdev->port, mdev->unit); + maple_detach_driver(mdev); + return; + } + if (!started) { + printk(KERN_INFO "No maple devices attached to port %d\n", + mdev->port); + return; + } + maple_clean_submap(mdev); +} + +/* preprocess hotplugs or scans */ +static void maple_response_devinfo(struct maple_device *mdev, + char *recvbuf) +{ + char submask; + if ((!started) || (scanning == 2)) { + maple_attach_driver(mdev); + return; + } + if (mdev->unit == 0) { + submask = recvbuf[2] & 0x1F; + if (submask ^ subdevice_map[mdev->port]) { + maple_map_subunits(mdev, submask); + subdevice_map[mdev->port] = submask; + } + } +} + +/* maple dma end bottom half - implemented via workqueue */ +static void maple_dma_handler(struct work_struct *work) +{ + struct mapleq *mq, *nmq; + struct maple_device *dev; + char *recvbuf; + enum maple_code code; + + if (!maple_dma_done()) + return; + ctrl_outl(0, MAPLE_ENABLE); + if (!list_empty(&maple_sentq)) { + list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { + recvbuf = mq->recvbuf; + code = recvbuf[0]; + dev = mq->dev; + switch (code) { + case MAPLE_RESPONSE_NONE: + maple_response_none(dev, mq); + break; + + case MAPLE_RESPONSE_DEVINFO: + maple_response_devinfo(dev, recvbuf); + break; + + case MAPLE_RESPONSE_DATATRF: + if (dev->callback) + dev->callback(mq); + break; + + case MAPLE_RESPONSE_FILEERR: + case MAPLE_RESPONSE_AGAIN: + case MAPLE_RESPONSE_BADCMD: + case MAPLE_RESPONSE_BADFUNC: + printk(KERN_DEBUG + "Maple non-fatal error 0x%X\n", + code); + break; + + case MAPLE_RESPONSE_ALLINFO: + printk(KERN_DEBUG + "Maple - extended device information not supported\n"); + break; + + case MAPLE_RESPONSE_OK: + break; + + default: + break; + } + } + INIT_LIST_HEAD(&maple_sentq); + if (scanning == 1) { + maple_send(); + scanning = 2; + } else + scanning = 0; + + if (started == 0) + started = 1; + } + maplebus_dma_reset(); +} + +static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) +{ + /* Load everything into the bottom half */ + schedule_work(&maple_dma_process); + return IRQ_HANDLED; +} + +static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) +{ + schedule_work(&maple_vblank_process); + return IRQ_HANDLED; +} + +static struct irqaction maple_dma_irq = { + .name = "maple bus DMA handler", + .handler = maplebus_dma_interrupt, + .flags = IRQF_SHARED, +}; + +static struct irqaction maple_vblank_irq = { + .name = "maple bus VBLANK handler", + .handler = maplebus_vblank_interrupt, + .flags = IRQF_SHARED, +}; + +static int maple_set_dma_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); +} + +static int maple_set_vblank_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); +} + +static int maple_get_dma_buffer(void) +{ + maple_sendbuf = + (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + MAPLE_DMA_PAGES); + if (!maple_sendbuf) + return -ENOMEM; + return 0; +} + +static int match_maple_bus_driver(struct device *devptr, + struct device_driver *drvptr) +{ + struct maple_driver *maple_drv; + struct maple_device *maple_dev; + + maple_drv = container_of(drvptr, struct maple_driver, drv); + maple_dev = container_of(devptr, struct maple_device, dev); + /* Trap empty port case */ + if (maple_dev->devinfo.function == 0xFFFFFFFF) + return 0; + else if (maple_dev->devinfo.function & + be32_to_cpu(maple_drv->function)) + return 1; + return 0; +} + +static int maple_bus_uevent(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return 0; +} + +static void maple_bus_release(struct device *dev) +{ +} + +static struct maple_driver maple_dummy_driver = { + .drv = { + .name = "maple_dummy_driver", + .bus = &maple_bus_type, + }, +}; + +struct bus_type maple_bus_type = { + .name = "maple", + .match = match_maple_bus_driver, + .uevent = maple_bus_uevent, +}; + +EXPORT_SYMBOL_GPL(maple_bus_type); + +static struct device maple_bus = { + .bus_id = "maple", + .release = maple_bus_release, +}; + +static int __init maple_bus_init(void) +{ + int retval, i; + struct maple_device *mdev[MAPLE_PORTS]; + ctrl_outl(0, MAPLE_STATE); + + retval = device_register(&maple_bus); + if (retval) + goto cleanup; + + retval = bus_register(&maple_bus_type); + if (retval) + goto cleanup_device; + + retval = driver_register(&maple_dummy_driver.drv); + + if (retval) + goto cleanup_bus; + + /* allocate memory for maple bus dma */ + retval = maple_get_dma_buffer(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to allocate Maple DMA buffers\n"); + goto cleanup_basic; + } + + /* set up DMA interrupt handler */ + retval = maple_set_dma_interrupt_handler(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to grab maple DMA IRQ\n"); + goto cleanup_dma; + } + + /* set up VBLANK interrupt handler */ + retval = maple_set_vblank_interrupt_handler(); + if (retval) { + printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); + goto cleanup_irq; + } + + maple_queue_cache = + kmem_cache_create("maple_queue_cache", 0x400, 0, + SLAB_HWCACHE_ALIGN, NULL); + + if (!maple_queue_cache) + goto cleanup_bothirqs; + + /* setup maple ports */ + for (i = 0; i < MAPLE_PORTS; i++) { + mdev[i] = maple_alloc_dev(i, 0); + if (!mdev[i]) { + while (i-- > 0) + maple_free_dev(mdev[i]); + goto cleanup_cache; + } + mdev[i]->registered = 0; + mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; + mdev[i]->mq->length = 0; + maple_attach_driver(mdev[i]); + maple_add_packet(mdev[i]->mq); + subdevice_map[i] = 0; + } + + /* setup maplebus hardware */ + maplebus_dma_reset(); + + /* initial detection */ + maple_send(); + + maple_pnp_time = jiffies; + + printk(KERN_INFO "Maple bus core now registered.\n"); + + return 0; + +cleanup_cache: + kmem_cache_destroy(maple_queue_cache); + +cleanup_bothirqs: + free_irq(HW_EVENT_VSYNC, 0); + +cleanup_irq: + free_irq(HW_EVENT_MAPLE_DMA, 0); + +cleanup_dma: + free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); + +cleanup_basic: + driver_unregister(&maple_dummy_driver.drv); + +cleanup_bus: + bus_unregister(&maple_bus_type); + +cleanup_device: + device_unregister(&maple_bus); + +cleanup: + printk(KERN_INFO "Maple bus registration failed\n"); + return retval; +} + +subsys_initcall(maple_bus_init); |
From: Adrian M. <lkm...@gm...> - 2007-09-20 11:29:46
|
The Maple bus is SEGA's proprietary serial bus for peripherals (keyboard, mouse, controller etc). The bus is capable of some (limited) hotplugging and operates at up to 2 M/bits. Drivers of one sort or another existed/exist for 2.4 and a rudimentary port, which didn't support the 2.6 device driver modei was also in existence. This driver - for the bus logic itself and for the keyboard (other drivers will follow) are based on the code and concepts of those old drivers but have lots of completely rewritten parts. I have the maplebus code as a built in now as that seems the sane and rational way to handle something like that - you either want the bus or you don't. maplebus.c: adds the core bus support maple_keyb.c: adds the keyboard Signed off by Adrian McMenamin <ad...@mc...> |
From: Paul M. <le...@li...> - 2007-09-17 22:51:11
|
On Mon, Sep 17, 2007 at 06:02:46AM -0400, Mike Frysinger wrote: > On Monday 17 September 2007, Paul Mundt wrote: > > On Sun, Sep 16, 2007 at 08:40:03PM -0700, Kristoffer Ericson wrote: > > > Paul, whats the status of kexec on the linuxsh tree? From what I recall > > > it currently only works on x86 platforms, but the arm people seem eager > > > to get it working on their platform also. > > > > Huh? Kexec has run on plenty or architectures for a long time, including > > sh. There aren't any problems with it that I know of, and plenty of > > people are using it. > > if only the userland tools would get off their asses ... http://git.kernel.org/?p=linux/kernel/git/horms/kexec-tools-testing.git;a=summary is the tree to be using, the other ones are outdated and no longer developed. |
From: Markus B. <sup...@go...> - 2007-09-17 10:23:39
|
Hi Paul, this update moves the flash mapping for the Magic Panel into the board setup. It also removes references to the old MTD mapping option in the defconfig. Signed-off by: Markus Brunner <sup...@gm...> Signed-off by: Mark Jonas <to...@gm...> --- boards/magicpanelr2/setup.c | 83 ++++++++++++++++++++++++++++++++++++++++- configs/magicpanelr2_defconfig | 8 ++- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/arch/sh/boards/magicpanelr2/setup.c b/arch/sh/boards/magicpanelr2/setup.c index c593065..854bcc6 100644 --- a/arch/sh/boards/magicpanelr2/setup.c +++ b/arch/sh/boards/magicpanelr2/setup.c @@ -12,14 +12,19 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/platform_device.h> -#include <linux/ide.h> -#include <linux/irq.h> #include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/map.h> #include <asm/magicpanelr2.h> #include <asm/heartbeat.h> #define LAN9115_READY (ctrl_inl(0xA8000084UL) & 0x00000001UL) +/* Prefer cmdline over RedBoot */ +static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; + /* Wait until reset finished. Timeout is 100ms. */ static int __init ethernet_reset_finished(void) { @@ -270,13 +275,87 @@ static struct platform_device heartbeat_device = { .resource = heartbeat_resources, }; +static struct mtd_partition *parsed_partitions; + +static struct mtd_partition mpr2_partitions[] = { + /* Reserved for bootloader, read-only */ + { + .name = "Bootloader", + .offset = 0x00000000UL, + .size = MPR2_MTD_BOOTLOADER_SIZE, + .mask_flags = MTD_WRITEABLE, + }, + /* Reserved for kernel image */ + { + .name = "Kernel", + .offset = MTDPART_OFS_NXTBLK, + .size = MPR2_MTD_KERNEL_SIZE, + }, + /* Rest is used for Flash FS */ + { + .name = "Flash_FS", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct physmap_flash_data flash_data = { + .width = 2, +}; + +static struct resource flash_resource = { + .start = 0x00000000, + .end = 0x2000000UL, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = -1, + .resource = &flash_resource, + .num_resources = 1, + .dev = { + .platform_data = &flash_data, + }, +}; + +static struct mtd_info *flash_mtd; + +struct map_info mpr2_flash_map = { + .name = "Magic Panel R2 Flash", + .size = 0x2000000UL, + .bankwidth = 2, +}; + +static void __init set_mtd_partitions(){ + int nr_parts = 0; + simple_map_init(&mpr2_flash_map); + flash_mtd = do_map_probe("cfi_probe", &mpr2_flash_map); + nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_partitions, 0); + /* If there is no partition table, used the hard coded table */ + if (nr_parts <= 0) { + flash_data.parts = mpr2_partitions; + flash_data.nr_parts = ARRAY_SIZE(mpr2_partitions); + } else { + flash_data.nr_parts = nr_parts; + flash_data.parts = parsed_partitions; + } +} + +/* + * Add all resources to the platform_device + */ + static struct platform_device *mpr2_devices[] __initdata = { &heartbeat_device, &smc911x_device, + &flash_device, }; + static int __init mpr2_devices_setup(void) { + set_mtd_partitions(); return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices)); } device_initcall(mpr2_devices_setup); diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig index ce4e764..f8398a5 100644 --- a/arch/sh/configs/magicpanelr2_defconfig +++ b/arch/sh/configs/magicpanelr2_defconfig @@ -185,7 +185,7 @@ CONFIG_SH_MAGIC_PANEL_R2=y # # Magic Panel R2 options # -CONFIG_SH_MAGIC_PANEL_R2_VERSION=2 +CONFIG_SH_MAGIC_PANEL_R2_VERSION=3 # # Timer and clock configuration @@ -404,9 +404,11 @@ CONFIG_MTD_CFI_UTIL=y # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set -# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x0000000 +CONFIG_MTD_PHYSMAP_LEN=0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 # CONFIG_MTD_SOLUTIONENGINE is not set -CONFIG_MTD_MAGICPANELR2=y # CONFIG_MTD_PLATRAM is not set # |
From: Mike F. <va...@ge...> - 2007-09-17 10:02:54
|
On Monday 17 September 2007, Paul Mundt wrote: > On Sun, Sep 16, 2007 at 08:40:03PM -0700, Kristoffer Ericson wrote: > > Paul, whats the status of kexec on the linuxsh tree? From what I recall > > it currently only works on x86 platforms, but the arm people seem eager > > to get it working on their platform also. > > Huh? Kexec has run on plenty or architectures for a long time, including > sh. There aren't any problems with it that I know of, and plenty of > people are using it. if only the userland tools would get off their asses ... -mike |
From: Paul M. <le...@li...> - 2007-09-17 07:26:13
|
On Sun, Sep 16, 2007 at 08:40:03PM -0700, Kristoffer Ericson wrote: > Paul, whats the status of kexec on the linuxsh tree? From what I recall > it currently only works on x86 platforms, but the arm people seem eager > to get it working on their platform also. > Huh? Kexec has run on plenty or architectures for a long time, including sh. There aren't any problems with it that I know of, and plenty of people are using it. |
From: Kristoffer E. <kri...@gm...> - 2007-09-16 18:32:18
|
Paul, whats the status of kexec on the linuxsh tree? From what I recall it currently only works on x86 platforms, but the arm people seem eager to get it working on their platform also. -- Kristoffer Ericson <Kri...@Gm...> |
From: Adrian M. <lkm...@gm...> - 2007-09-15 19:44:33
|
Apologies - these are the patches to add header files to the series beginning here: http://lkml.org/lkml/2007/9/15/181 Add maplebus headers Signed off by Adrian McMenamin <ad...@mc...> diff --git a/include/linux/input.h b/include/linux/input.h diff --git a/include/linux/maple.h b/include/linux/maple.h new file mode 100644 index 0000000..e297cce --- /dev/null +++ b/include/linux/maple.h @@ -0,0 +1,87 @@ +/** + * maple.h + * + * porting to 2.6 driver model + * copyright Adrian McMenamin, 2007 + * + */ +#ifndef __LINUX_MAPLE_H +#define __LINUX_MAPLE_H + +extern struct bus_type maple_bus_type; + +/* Maple Bus command and response codes */ +enum maple_code { + MAPLE_RESPONSE_FILEERR = -5, + MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ + MAPLE_RESPONSE_BADCMD = -3, + MAPLE_RESPONSE_BADFUNC = -2, + MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ + MAPLE_COMMAND_DEVINFO = 1, + MAPLE_COMMAND_ALLINFO = 2, + MAPLE_COMMAND_RESET = 3, + MAPLE_COMMAND_KILL = 4, + MAPLE_RESPONSE_DEVINFO = 5, + MAPLE_RESPONSE_ALLINFO = 6, + MAPLE_RESPONSE_OK = 7, + MAPLE_RESPONSE_DATATRF = 8, + MAPLE_COMMAND_GETCOND = 9, + MAPLE_COMMAND_GETMINFO = 10, + MAPLE_COMMAND_BREAD = 11, + MAPLE_COMMAND_BWRITE = 12, + MAPLE_COMMAND_SETCOND = 14 +}; + +struct mapleq { + struct list_head list; + struct maple_device *dev; + void *sendbuf, *recvbuf, *recvbufdcsp; + unsigned char length; + enum maple_code command; +}; + +struct maple_devinfo { + unsigned long function; + unsigned long function_data[3]; + unsigned char area_code; + unsigned char connector_directon; + char product_name[31]; + char product_licence[61]; + unsigned short standby_power; + unsigned short max_power; +}; + +struct maple_device { + struct maple_driver *driver; + struct mapleq *mq; + void *private_data; + void (*callback) (struct mapleq * mq); + unsigned long when, interval, function; + struct maple_devinfo devinfo; + unsigned char port, unit; + char product_name[32]; + char product_licence[64]; + int registered; + struct device dev; +}; + +struct maple_driver { + unsigned long function; + int (*connect) (struct maple_device * dev); + void (*disconnect) (struct maple_device * dev); + struct device_driver drv; +}; + +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, + unsigned long function); + +int maple_driver_register(struct device_driver *drv); + +void maple_add_packet(struct mapleq *mq); + +#define to_maple_dev(n) container_of(n, struct maple_device, dev) +#define to_maple_driver(n) container_of(n, struct maple_driver, drv) + +#endif /* __LINUX_MAPLE_H */ diff --git a/include/asm-sh/dreamcast/maple.h b/include/asm-sh/dreamcast/maple.h new file mode 100644 index 0000000..4836d24 --- /dev/null +++ b/include/asm-sh/dreamcast/maple.h @@ -0,0 +1,36 @@ +#ifndef __ASM_MAPLE_H +#define __ASM_MAPLE_H + +#define MAPLE_PORTS 4 +#define MAPLE_PNP_INTERVAL HZ +#define MAPLE_MAXPACKETS 8 +#define MAPLE_DMA_ORDER 14 +#define MAPLE_DMA_SIZE (1 << MAPLE_DMA_ORDER) +#define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? MAPLE_DMA_ORDER - PAGE_SHIFT : 0) + +/* Maple Bus registers */ +#define MAPLE_BASE 0xa05f6c00 +#define MAPLE_DMAADDR (MAPLE_BASE+0x04) +#define MAPLE_TRIGTYPE (MAPLE_BASE+0x10) +#define MAPLE_ENABLE (MAPLE_BASE+0x14) +#define MAPLE_STATE (MAPLE_BASE+0x18) +#define MAPLE_SPEED (MAPLE_BASE+0x80) +#define MAPLE_RESET (MAPLE_BASE+0x8c) + +#define MAPLE_MAGIC 0x6155404f +#define MAPLE_2MBPS 0 +#define MAPLE_TIMEOUT(n) ((n)<<15) + +/* Function codes */ +#define MAPLE_FUNC_CONTROLLER 0x001 +#define MAPLE_FUNC_MEMCARD 0x002 +#define MAPLE_FUNC_LCD 0x004 +#define MAPLE_FUNC_CLOCK 0x008 +#define MAPLE_FUNC_MICROPHONE 0x010 +#define MAPLE_FUNC_ARGUN 0x020 +#define MAPLE_FUNC_KEYBOARD 0x040 +#define MAPLE_FUNC_LIGHTGUN 0x080 +#define MAPLE_FUNC_PURUPURU 0x100 +#define MAPLE_FUNC_MOUSE 0x200 + +#endif /* __ASM_MAPLE_H */ |
From: Adrian M. <lkm...@gm...> - 2007-09-15 19:39:26
|
This patch handles instability on the Dreamcast G2 bus while PIO or DMA is underway on the System -> AICA channel. Without the suspension of interrupts when PIO or DMA is underway the G2 bus is prone to timeouts leading to seemingly random crashes. This is particularly visible in cases such as maple bus (see http://lkml.org/lkml/2007/9/15/181) hotplugging but the patch is good for all conditions. Signed-off by: Adrian McMenamin <ad...@mc...> diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 7397865..54aed1d 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -35,6 +35,7 @@ #include <linux/timer.h> #include <linux/delay.h> #include <linux/workqueue.h> +#include <linux/maple.h> #include <sound/driver.h> #include <sound/core.h> #include <sound/control.h> @@ -43,7 +44,8 @@ #include <sound/info.h> #include <asm/io.h> #include <asm/dma.h> -#include <asm/dreamcast/sysasic.h> +#include <asm/mach/sysasic.h> +#include <asm/mach/maple.h> #include "aica.h" MODULE_AUTHOR("Adrian McMenamin <ad...@mc...>"); @@ -106,11 +108,14 @@ static void spu_write_wait(void) static void spu_memset(u32 toi, u32 what, int length) { int i; + unsigned long flags; snd_assert(length % 4 == 0, return); for (i = 0; i < length; i++) { if (!(i % 8)) spu_write_wait(); + local_irq_save(flags); writel(what, toi + SPU_MEMORY_BASE); + local_irq_restore(flags); toi++; } } @@ -118,6 +123,7 @@ static void spu_memset(u32 toi, u32 what, int length) /* spu_memload - write to SPU address space */ static void spu_memload(u32 toi, void *from, int length) { + unsigned long flags; u32 *froml = from; u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi); int i; @@ -128,7 +134,9 @@ static void spu_memload(u32 toi, void *from, int length) if (!(i % 8)) spu_write_wait(); val = *froml; + local_irq_save(flags); writel(val, to); + local_irq_restore(flags); froml++; to++; } @@ -138,28 +146,36 @@ static void spu_memload(u32 toi, void *from, int length) static void spu_disable(void) { int i; + unsigned long flags; u32 regval; spu_write_wait(); regval = readl(ARM_RESET_REGISTER); regval |= 1; spu_write_wait(); + local_irq_save(flags); writel(regval, ARM_RESET_REGISTER); + local_irq_restore(flags); for (i = 0; i < 64; i++) { spu_write_wait(); regval = readl(SPU_REGISTER_BASE + (i * 0x80)); regval = (regval & ~0x4000) | 0x8000; spu_write_wait(); + local_irq_save(flags); writel(regval, SPU_REGISTER_BASE + (i * 0x80)); + local_irq_restore(flags); } } /* spu_enable - set spu registers to enable sound output */ static void spu_enable(void) { + unsigned long flags; u32 regval = readl(ARM_RESET_REGISTER); regval &= ~1; spu_write_wait(); + local_irq_save(flags); writel(regval, ARM_RESET_REGISTER); + local_irq_restore(flags); } /* @@ -178,15 +194,21 @@ static void spu_reset(void) /* aica_chn_start - write to spu to start playback */ static void aica_chn_start(void) { + unsigned long flags; spu_write_wait(); + local_irq_save(flags); writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT); + local_irq_restore(flags); } /* aica_chn_halt - write to spu to halt playback */ static void aica_chn_halt(void) { + unsigned long flags; spu_write_wait(); + local_irq_save(flags); writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT); + local_irq_restore(flags); } /* ALSA code below */ @@ -211,6 +233,7 @@ static int aica_dma_transfer(int channels, int buffer_size, struct snd_pcm_substream *substream) { int q, err, period_offset; + unsigned long flags; struct snd_card_aica *dreamcastcard; struct snd_pcm_runtime *runtime; err = 0; @@ -218,6 +241,7 @@ static int aica_dma_transfer(int channels, int buffer_size, period_offset = dreamcastcard->clicks; period_offset %= (AICA_PERIOD_NUMBER / channels); runtime = substream->runtime; + local_irq_save(flags); for (q = 0; q < channels; q++) { err = dma_xfer(AICA_DMA_CHANNEL, (unsigned long) (runtime->dma_area + @@ -232,6 +256,7 @@ static int aica_dma_transfer(int channels, int buffer_size, break; dma_wait_for_completion(AICA_DMA_CHANNEL); } + local_irq_restore(flags); return err; } @@ -277,18 +302,21 @@ static void aica_period_elapsed(unsigned long timer_var) { /*timer function - so cannot sleep */ int play_period; + unsigned long flags; struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream; struct snd_card_aica *dreamcastcard; substream = (struct snd_pcm_substream *) timer_var; runtime = substream->runtime; dreamcastcard = substream->pcm->private_data; - /* Have we played out an additional period? */ + local_irq_save(flags); + /* now check if additional period has been played */ play_period = frames_to_bytes(runtime, readl (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) / AICA_PERIOD_SIZE; + local_irq_restore(flags); if (play_period == dreamcastcard->current_period) { /* reschedule the timer */ mod_timer(&(dreamcastcard->timer), jiffies + 1); @@ -433,7 +461,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica err = snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0, &pcm); - if (unlikely(err < 0)) + if (err < 0) return err; pcm->private_data = dreamcastcard; strcpy(pcm->name, "AICA PCM"); @@ -493,7 +521,7 @@ static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol, { struct snd_card_aica *dreamcastcard; dreamcastcard = kcontrol->private_data; - if (unlikely(!dreamcastcard->channel)) + if (!dreamcastcard->channel) return -ETXTBSY; /* we've not yet been set up */ ucontrol->value.integer.value[0] = dreamcastcard->channel->vol; return 0; @@ -504,10 +532,10 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, { struct snd_card_aica *dreamcastcard; dreamcastcard = kcontrol->private_data; - if (unlikely(!dreamcastcard->channel)) + if (!dreamcastcard->channel) return -ETXTBSY; - if (unlikely(dreamcastcard->channel->vol == - ucontrol->value.integer.value[0])) + if (dreamcastcard->channel->vol == + ucontrol->value.integer.value[0]) return 0; dreamcastcard->channel->vol = ucontrol->value.integer.value[0]; dreamcastcard->master_volume = ucontrol->value.integer.value[0]; @@ -537,15 +565,18 @@ static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = { static int load_aica_firmware(void) { int err; + unsigned long flags; const struct firmware *fw_entry; spu_reset(); err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev); - if (unlikely(err)) + if (err) return err; /* write firware into memory */ + local_irq_save(flags); spu_disable(); spu_memload(0, fw_entry->data, fw_entry->size); spu_enable(); + local_irq_restore(flags); release_firmware(fw_entry); return err; } @@ -557,12 +588,12 @@ static int __devinit add_aicamixer_controls(struct snd_card_aica err = snd_ctl_add (dreamcastcard->card, snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard)); - if (unlikely(err < 0)) + if (err < 0) return err; err = snd_ctl_add (dreamcastcard->card, snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard)); - if (unlikely(err < 0)) + if (err < 0) return err; return 0; } @@ -571,7 +602,7 @@ static int snd_aica_remove(struct platform_device *devptr) { struct snd_card_aica *dreamcastcard; dreamcastcard = platform_get_drvdata(devptr); - if (unlikely(!dreamcastcard)) + if (!dreamcastcard) return -ENODEV; snd_card_free(dreamcastcard->card); kfree(dreamcastcard); @@ -584,11 +615,11 @@ static int __init snd_aica_probe(struct platform_device *devptr) int err; struct snd_card_aica *dreamcastcard; dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL); - if (unlikely(!dreamcastcard)) + if (!dreamcastcard) return -ENOMEM; dreamcastcard->card = snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0); - if (unlikely(!dreamcastcard->card)) { + if (!dreamcastcard->card) { kfree(dreamcastcard); return -ENODEV; } @@ -600,27 +631,28 @@ static int __init snd_aica_probe(struct platform_device *devptr) INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma); /* Load the PCM 'chip' */ err = snd_aicapcmchip(dreamcastcard, 0); - if (unlikely(err < 0)) + if (err < 0) goto freedreamcast; snd_card_set_dev(dreamcastcard->card, &devptr->dev); dreamcastcard->timer.data = 0; dreamcastcard->channel = NULL; /* Add basic controls */ err = add_aicamixer_controls(dreamcastcard); - if (unlikely(err < 0)) + if (err < 0) goto freedreamcast; /* Register the card with ALSA subsystem */ err = snd_card_register(dreamcastcard->card); - if (unlikely(err < 0)) + if (err < 0) goto freedreamcast; platform_set_drvdata(devptr, dreamcastcard); aica_queue = create_workqueue(CARD_NAME); - if (unlikely(!aica_queue)) + if (!aica_queue) goto freedreamcast; snd_printk ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n"); return 0; - freedreamcast: + +freedreamcast: snd_card_free(dreamcastcard->card); kfree(dreamcastcard); return err; @@ -637,11 +669,11 @@ static int __init aica_init(void) { int err; err = platform_driver_register(&snd_aica_driver); - if (unlikely(err < 0)) + if (err < 0) return err; pd = platform_device_register_simple(SND_AICA_DRIVER, -1, aica_memory_space, 2); - if (unlikely(IS_ERR(pd))) { + if (IS_ERR(pd)) { platform_driver_unregister(&snd_aica_driver); return PTR_ERR(pd); } @@ -653,7 +685,7 @@ static void __exit aica_exit(void) { /* Destroy the aica kernel thread * * being extra cautious to check if it exists*/ - if (likely(aica_queue)) + if (aica_queue) destroy_workqueue(aica_queue); platform_device_unregister(pd); platform_driver_unregister(&snd_aica_driver); |
From: Adrian M. <lkm...@gm...> - 2007-09-15 19:32:51
|
This patch adds support for the keyboard on the SEGA Dreamcast Signed-off by Adrian McMenamin <ad...@mc...> Acked-by: Arjan van de Ven <ar...@li...> Acked-by: Dmitry Torokhov <dmi...@gm...> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c97d5eb..056cc52 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -253,4 +253,14 @@ config KEYBOARD_GPIO To compile this driver as a module, choose M here: the module will be called gpio-keys. + +config KEYBOARD_MAPLE + tristate "Maple bus keyboard" + depends on SH_DREAMCAST && MAPLE + help + Say Y here if you have a Dreamcast console running Linux and have + a keyboard attached to its Maple bus. + + To compile this driver as a module, choose M here: the + module will be called maple_keyb. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 28d211b..3f775ed 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o +obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 0000000..3bb58e1 --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c @@ -0,0 +1,234 @@ +/* + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + * Copyright YAEGASHI Takeshi, 2001 + * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/maple.h> +#include <asm/mach/maple.h> + +/* Very simple mutex to ensure proper cleanup */ +static DEFINE_MUTEX(maple_keyb_mutex); + +#define NR_SCANCODES 256 + +MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin"); +MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); +MODULE_LICENSE("GPL"); + +struct dc_kbd { + struct input_dev *dev; + unsigned char keycode[NR_SCANCODES]; + unsigned char new[8]; + unsigned char old[8]; +}; + +const static unsigned char dc_kbd_keycode[NR_SCANCODES] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D, + KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, + KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, + KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, + KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, + KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, + KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, + KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, + KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, + KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, + KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, + KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, + KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, + KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, + KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, + KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static void dc_scan_kbd(struct dc_kbd *kbd) +{ + int i; + void *ptr; + struct input_dev *dev = kbd->dev; + + for (i = 0; i < 8; i++) + input_report_key(dev, kbd->keycode[i + 224], + (kbd->new[0] >> i) & 1); + + for (i = 2; i < 8; i++) { + ptr = memchr(kbd->new + 2, kbd->old[i], 6); + if (kbd->old[i] > 3 && ptr == NULL) { + if (dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, kbd->keycode[kbd->old[i]], 0); + else + printk (KERN_DEBUG "Unknown key (scancode %#x) released.", kbd->old[i]); + } + ptr = memchr(kbd->old + 2, kbd->new[i], 6); + if (kbd->new[i] > 3 && ptr) { + if (dc_kbd_keycode[kbd->new[i]]) + input_report_key(dev, kbd->keycode[kbd->new[i]], 1); + else + printk(KERN_DEBUG "Unknown key (scancode %#x) pressed.", kbd->new[i]); + } + } + input_sync(dev); + memcpy(kbd->old, kbd->new, 8); +} + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = mapledev->private_data; + unsigned long *buf = mq->recvbuf; + + if (!mutex_trylock(&maple_keyb_mutex)) /* Can only be locked if already in cleanup */ + return; + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf + 2, 8); + dc_scan_kbd(kbd); + } + mutex_unlock(&maple_keyb_mutex); +} + +static int dc_kbd_connect(struct maple_device *mdev) +{ + int i, retval = 0; + struct dc_kbd *kbd; + struct input_dev *dev; + + if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) + return -EINVAL; + + kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + if (unlikely(!kbd)) + return -ENOMEM; + + mdev->private_data = kbd; + kbd->dev = input_allocate_device(); + if (!kbd->dev){ + retval = -ENODEV; + goto cleanup_memory; + } + + dev = kbd->dev; + + memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); + + dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + dev->keycodesize = sizeof (unsigned char); + dev->keycodemax = ARRAY_SIZE(kbd->keycode); + dev->keycode = kbd->keycode; + dev->dev.parent = &mdev->dev; + + for (i = 0; i < NR_SCANCODES; i++) + set_bit(dc_kbd_keycode[i], dev->keybit); + + clear_bit(0, dev->keybit); + + input_set_drvdata(dev, kbd); + + dev->name = mdev->product_name; + dev->id.bustype = BUS_HOST; + + retval = input_register_device(dev); + if (retval) + goto cleanup; + /* Maple polling is locked to VBLANK - which may be just 50/s */ + maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); + return retval; + +cleanup: + input_free_device(kbd->dev); +cleanup_memory: + kfree(kbd); + return retval; +} + +static void dc_kbd_disconnect(struct maple_device *mdev) +{ + struct dc_kbd *kbd; + + mutex_lock(&maple_keyb_mutex); + kbd = mdev->private_data; + + input_unregister_device(kbd->dev); + kfree(kbd); + mutex_unlock(&maple_keyb_mutex); +} + +/* allow the keyboard to be used */ +static int probe_maple_kbd(struct device *dev) +{ + struct maple_device *mdev; + struct maple_driver *mdrv; + int proberes; + + mdev = to_maple_dev(dev); + mdrv = to_maple_driver(dev->driver); + + proberes = dc_kbd_connect(mdev); + if (unlikely(proberes)) + return proberes; + mdev->driver = mdrv; + mdev->registered = 1; + return 0; +} + +static struct maple_driver dc_kbd_driver = { + .function = MAPLE_FUNC_KEYBOARD, + .connect = dc_kbd_connect, + .disconnect = dc_kbd_disconnect, + .drv = { + .name = "Dreamcast_keyboard", + .probe = probe_maple_kbd, + }, +}; + +static int __init dc_kbd_init(void) +{ + return maple_driver_register(&dc_kbd_driver.drv); +} + +static void __exit dc_kbd_exit(void) +{ + driver_unregister(&dc_kbd_driver.drv); +} + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); |
From: Adrian M. <lkm...@gm...> - 2007-09-15 19:32:45
|
This adds support for the maple bus (SEGA's proprietary serial bus on the Dreamcast) to the kernel. Signed-off by: Adrian McMenamin <ad...@mc...> diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 54878f0..077438f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -702,6 +702,17 @@ config CF_BASE_ADDR default "0xb8000000" if CF_AREA6 default "0xb4000000" if CF_AREA5 +config MAPLE + bool "Maple Bus Support" + depends on SH_DREAMCAST + help + The Maple Bus is SEGA's serial communication bus for peripherals + on the Dreamcast. Without this bus support you won't be able to + get your Dreamcast keyboard etc to work, so most users + probably want to say 'Y' here, unless you are only using the + Dreamcast with a serial line terminal or a remote network + connection. + source "arch/sh/drivers/pci/Kconfig" source "drivers/pci/Kconfig" diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 8a14389..f0a1f4f 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -3,4 +3,5 @@ # obj-$(CONFIG_SUPERHYWAY) += superhyway/ +obj-$(CONFIG_MAPLE) += maple/ diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile new file mode 100644 index 0000000..604ce33 --- /dev/null +++ b/drivers/sh/maple/Makefile @@ -0,0 +1,3 @@ +#Makefile for Maple Bus + +obj-$(CONFIG_MAPLE) := maplebus.o diff --git a/drivers/sh/maple/maplebus.c b/drivers/sh/maple/maplebus.c new file mode 100644 index 0000000..48eeee6 --- /dev/null +++ b/drivers/sh/maple/maplebus.c @@ -0,0 +1,731 @@ +/* maplebus.c + * Core maple bus functionality + * Original 2.4 code used here copyright + * YAEGASHI Takeshi, Paul Mundt, M. R. Brown and others + * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * + * Licensed under version 2 of the GPL + * See the COPYING file that came with this + * distribution for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/maple.h> +#include <linux/dma-mapping.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/mach/dma.h> +#include <asm/mach/sysasic.h> +#include <asm/mach/maple.h> + +MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, MR Brown, Adrian McMenamin"); +MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); + +static void maple_dma_handler(struct work_struct *work); +static void maple_vblank_handler(struct work_struct *work); + +static DECLARE_WORK(maple_dma_process, maple_dma_handler); +static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); + +static LIST_HEAD(maple_waitq); +static LIST_HEAD(maple_sentq); + +static DEFINE_MUTEX(maple_list_lock); + +static struct maple_driver maple_dummy_driver; +static struct device maple_bus; +static int subdevice_map[MAPLE_PORTS]; +static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; +static unsigned long maple_pnp_time; +static int started, scanning, liststatus; +static struct kmem_cache *maple_queue_cache; + +struct maple_device_specify { + int port; + int unit; +}; + +/** + * maple_driver_register - register a device driver + * automatically makes the driver bus a maple bus + * @drv: the driver to be registered + */ +int maple_driver_register(struct device_driver *drv) +{ + if (!drv) + return -EINVAL; + drv->bus = &maple_bus_type; + return driver_register(drv); +} + +EXPORT_SYMBOL_GPL(maple_driver_register); + +/* set hardware registers to enable next round of dma */ +static void maplebus_dma_reset(void) +{ + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ + ctrl_outl(1, MAPLE_TRIGTYPE); + ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); +} + +/** + * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND + * @dev: device responding + * @callback: handler callback + * @interval: interval in jiffies between callbacks + * @function: the function code for the device + */ +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, unsigned long function) +{ + dev->callback = callback; + dev->interval = interval; + dev->function = cpu_to_be32(function); + dev->when = jiffies; +} +EXPORT_SYMBOL_GPL(maple_getcond_callback); + +static int maple_dma_done(void) +{ + return (ctrl_inl(MAPLE_STATE) & 1) == 0; +} + +static void maple_release_device(struct device *dev) +{ + if (dev->type) { + kfree(dev->type->name); + kfree(dev->type); + } +} + +/** + * maple_add_packet - add a single instruction to the queue + * @mq: instruction to add to waiting queue + */ +void maple_add_packet(struct mapleq *mq) +{ + mutex_lock(&maple_list_lock); + list_add(&mq->list, &maple_waitq); + mutex_unlock(&maple_list_lock); +} +EXPORT_SYMBOL_GPL(maple_add_packet); + +static struct mapleq *maple_allocq(struct maple_device *dev) +{ + struct mapleq *mq; + + mq = kmalloc(sizeof(*mq), GFP_KERNEL); + if (!mq) + return NULL; + + mq->dev = dev; + mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); + mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); + if (!mq->recvbuf) { + kfree(mq); + return NULL; + } + + return mq; +} + +static struct maple_device *maple_alloc_dev(int port, int unit) +{ + struct maple_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->port = port; + dev->unit = unit; + dev->mq = maple_allocq(dev); + + if (!dev->mq) { + kfree(dev); + return NULL; + } + + return dev; +} + +static void maple_free_dev(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->mq) { + kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); + kfree(mdev->mq); + } + kfree(mdev); +} + +/* process the command queue into a maple command block + * terminating command has bit 32 of first long set to 0 + */ +static void maple_build_block(struct mapleq *mq) +{ + int port, unit, from, to, len; + unsigned long *lsendbuf = mq->sendbuf; + + port = mq->dev->port & 3; + unit = mq->dev->unit; + len = mq->length; + from = port << 6; + to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); + + *maple_lastptr &= 0x7fffffff; + maple_lastptr = maple_sendptr; + + *maple_sendptr++ = (port << 16) | len | 0x80000000; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = + mq->command | (to << 8) | (from << 16) | (len << 24); + + while (len-- > 0) + *maple_sendptr++ = *lsendbuf++; +} + +/* build up command queue */ +static void maple_send(void) +{ + int i; + int maple_packets; + struct mapleq *mq, *nmq; + + if (!list_empty(&maple_sentq)) + return; + if (list_empty(&maple_waitq) || !maple_dma_done()) + return; + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { + maple_build_block(mq); + list_move(&mq->list, &maple_sentq); + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + if (maple_packets > 0) { + for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) + dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, + PAGE_SIZE, DMA_BIDIRECTIONAL); + } +} + +static int attach_matching_maple_driver(struct device_driver *driver, + void *devptr) +{ + struct maple_driver *maple_drv; + struct maple_device *mdev; + + mdev = devptr; + maple_drv = to_maple_driver(driver); + if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { + if (maple_drv->connect(mdev) == 0) { + mdev->driver = maple_drv; + return 1; + } + } + return 0; +} + +static void maple_detach_driver(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->driver) { + if (mdev->driver->disconnect) + mdev->driver->disconnect(mdev); + } + mdev->driver = NULL; + if (mdev->registered) { + maple_release_device(&mdev->dev); + device_unregister(&mdev->dev); + } + mdev->registered = 0; + maple_free_dev(mdev); +} + +/* process initial MAPLE_COMMAND_DEVINFO for each device or port */ +static void maple_attach_driver(struct maple_device *dev) +{ + char *p; + + char *recvbuf; + unsigned long function; + int matched, retval; + + recvbuf = dev->mq->recvbuf; + memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); + memcpy(dev->product_name, dev->devinfo.product_name, 30); + memcpy(dev->product_licence, dev->devinfo.product_licence, 60); + dev->product_name[30] = '\0'; + dev->product_licence[60] = '\0'; + + for (p = dev->product_name + 29; dev->product_name <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + for (p = dev->product_licence + 59; dev->product_licence <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + function = be32_to_cpu(dev->devinfo.function); + + if (function > 0x200) { + /* Do this silently - as not a real device */ + function = 0; + dev->driver = &maple_dummy_driver; + sprintf(dev->dev.bus_id, "%d:0.port", dev->port); + } else { + printk(KERN_INFO + "Maple bus at (%d, %d): Connected function 0x%lX\n", + dev->port, dev->unit, function); + + matched = + bus_for_each_drv(&maple_bus_type, NULL, dev, + attach_matching_maple_driver); + + if (matched == 0) { + /* Driver does not exist yet */ + printk(KERN_INFO + "No maple driver found for this device\n"); + dev->driver = &maple_dummy_driver; + } + + sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, + dev->unit, function); + } + dev->function = function; + dev->dev.bus = &maple_bus_type; + dev->dev.parent = &maple_bus; + dev->dev.release = &maple_release_device; + retval = device_register(&dev->dev); + if (retval) { + printk(KERN_INFO + "Maple bus: Attempt to register device (%x, %x) failed.\n", + dev->port, dev->unit); + maple_free_dev(dev); + } + dev->registered = 1; +} + +/* if device has been registered for the given + * port and unit then return 1 - allows identification + * of which devices need to be attached or detached + */ +static int detach_maple_device(struct device *device, void *portptr) +{ + struct maple_device_specify *ds; + struct maple_device *mdev; + + ds = portptr; + mdev = to_maple_dev(device); + if (mdev->port == ds->port && mdev->unit == ds->unit) + return 1; + return 0; +} + +static int setup_maple_commands(struct device *device, void *ignored) +{ + struct maple_device *maple_dev = to_maple_dev(device); + + if ((maple_dev->interval > 0) + && time_after(jiffies, maple_dev->when)) { + maple_dev->when = jiffies + maple_dev->interval; + maple_dev->mq->command = MAPLE_COMMAND_GETCOND; + maple_dev->mq->sendbuf = &maple_dev->function; + maple_dev->mq->length = 1; + maple_add_packet(maple_dev->mq); + liststatus++; + } else { + if (time_after(jiffies, maple_pnp_time)) { + maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; + maple_dev->mq->length = 0; + maple_add_packet(maple_dev->mq); + liststatus++; + } + } + + return 0; +} + +/* VBLANK bottom half - implemented via workqueue */ +static void maple_vblank_handler(struct work_struct *work) +{ + if (!maple_dma_done()) + return; + if (!list_empty(&maple_sentq)) + return; + ctrl_outl(0, MAPLE_ENABLE); + liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, + setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) + maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; + if (liststatus && list_empty(&maple_sentq)) { + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + } + maplebus_dma_reset(); +} + +/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ +static void maple_map_subunits(struct maple_device *mdev, int submask) +{ + int retval, k, devcheck; + struct maple_device *mdev_add; + struct maple_device_specify ds; + + for (k = 0; k < 5; k++) { + ds.port = mdev->port; + ds.unit = k + 1; + retval = + bus_for_each_dev(&maple_bus_type, NULL, &ds, + detach_maple_device); + if (retval) { + submask = submask >> 1; + continue; + } + devcheck = submask & 0x01; + if (devcheck) { + mdev_add = maple_alloc_dev(mdev->port, k + 1); + if (!mdev_add) + return; + mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; + mdev_add->mq->length = 0; + maple_add_packet(mdev_add->mq); + scanning = 1; + } + submask = submask >> 1; + } +} + +/* mark a device as removed */ +static void maple_clean_submap(struct maple_device *mdev) +{ + int killbit; + + killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); + killbit = ~killbit; + killbit &= 0xFF; + subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; +} + +/* handle empty port or hotplug removal */ +static void maple_response_none(struct maple_device *mdev, + struct mapleq *mq) +{ + if (mdev->unit != 0) { + list_del(&mq->list); + maple_clean_submap(mdev); + printk(KERN_INFO + "Maple bus device detaching at (%d, %d)\n", + mdev->port, mdev->unit); + maple_detach_driver(mdev); + return; + } + if (!started) { + printk(KERN_INFO "No maple devices attached to port %d\n", + mdev->port); + return; + } + maple_clean_submap(mdev); +} + +/* preprocess hotplugs or scans */ +static void maple_response_devinfo(struct maple_device *mdev, + char *recvbuf) +{ + char submask; + if ((!started) || (scanning == 2)) { + maple_attach_driver(mdev); + return; + } + if (mdev->unit == 0) { + submask = recvbuf[2] & 0x1F; + if (submask ^ subdevice_map[mdev->port]) { + maple_map_subunits(mdev, submask); + subdevice_map[mdev->port] = submask; + } + } +} + +/* maple dma end bottom half - implemented via workqueue */ +static void maple_dma_handler(struct work_struct *work) +{ + struct mapleq *mq, *nmq; + struct maple_device *dev; + char *recvbuf; + enum maple_code code; + + if (!maple_dma_done()) + return; + ctrl_outl(0, MAPLE_ENABLE); + if (!list_empty(&maple_sentq)) { + list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { + recvbuf = mq->recvbuf; + code = recvbuf[0]; + dev = mq->dev; + switch (code) { + case MAPLE_RESPONSE_NONE: + maple_response_none(dev, mq); + break; + + case MAPLE_RESPONSE_DEVINFO: + maple_response_devinfo(dev, recvbuf); + break; + + case MAPLE_RESPONSE_DATATRF: + if (dev->callback) + dev->callback(mq); + break; + + case MAPLE_RESPONSE_FILEERR: + case MAPLE_RESPONSE_AGAIN: + case MAPLE_RESPONSE_BADCMD: + case MAPLE_RESPONSE_BADFUNC: + printk(KERN_DEBUG + "Maple non-fatal error 0x%X\n", + code); + break; + + case MAPLE_RESPONSE_ALLINFO: + printk(KERN_DEBUG + "Maple - extended device information not supported\n"); + break; + + case MAPLE_RESPONSE_OK: + break; + + default: + break; + } + } + INIT_LIST_HEAD(&maple_sentq); + if (scanning == 1) { + maple_send(); + scanning = 2; + } else + scanning = 0; + + if (started == 0) + started = 1; + } + maplebus_dma_reset(); +} + +static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) +{ + /* Load everything into the bottom half */ + schedule_work(&maple_dma_process); + return IRQ_HANDLED; +} + +static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) +{ + schedule_work(&maple_vblank_process); + return IRQ_HANDLED; +} + +static struct irqaction maple_dma_irq = { + .name = "maple bus DMA handler", + .handler = maplebus_dma_interrupt, + .flags = IRQF_SHARED, +}; + +static struct irqaction maple_vblank_irq = { + .name = "maple bus VBLANK handler", + .handler = maplebus_vblank_interrupt, + .flags = IRQF_SHARED, +}; + +static int maple_set_dma_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); +} + +static int maple_set_vblank_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); +} + +static int maple_get_dma_buffer(void) +{ + maple_sendbuf = + (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + MAPLE_DMA_PAGES); + if (!maple_sendbuf) + return -ENOMEM; + return 0; +} + +static int match_maple_bus_driver(struct device *devptr, + struct device_driver *drvptr) +{ + struct maple_driver *maple_drv; + struct maple_device *maple_dev; + + maple_drv = container_of(drvptr, struct maple_driver, drv); + maple_dev = container_of(devptr, struct maple_device, dev); + /* Trap empty port case */ + if (maple_dev->devinfo.function == 0xFFFFFFFF) + return 0; + else if (maple_dev->devinfo.function & + be32_to_cpu(maple_drv->function)) + return 1; + return 0; +} + +static int maple_bus_uevent(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return 0; +} + +static void maple_bus_release(struct device *dev) +{ +} + +static struct maple_driver maple_dummy_driver = { + .drv = { + .name = "maple_dummy_driver", + .bus = &maple_bus_type, + }, +}; + +struct bus_type maple_bus_type = { + .name = "maple", + .match = match_maple_bus_driver, + .uevent = maple_bus_uevent, +}; + +EXPORT_SYMBOL_GPL(maple_bus_type); + +static struct device maple_bus = { + .bus_id = "maple", + .release = maple_bus_release, +}; + +static int __init maple_bus_init(void) +{ + int retval, i; + struct maple_device *mdev[MAPLE_PORTS]; + ctrl_outl(0, MAPLE_STATE); + + retval = device_register(&maple_bus); + if (retval) + goto cleanup; + + retval = bus_register(&maple_bus_type); + if (retval) + goto cleanup_device; + + retval = driver_register(&maple_dummy_driver.drv); + + if (retval) + goto cleanup_bus; + + /* allocate memory for maple bus dma */ + retval = maple_get_dma_buffer(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to allocate Maple DMA buffers\n"); + goto cleanup_basic; + } + + /* set up DMA interrupt handler */ + retval = maple_set_dma_interrupt_handler(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to grab maple DMA IRQ\n"); + goto cleanup_dma; + } + + /* set up VBLANK interrupt handler */ + retval = maple_set_vblank_interrupt_handler(); + if (retval) { + printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); + goto cleanup_irq; + } + + maple_queue_cache = + kmem_cache_create("maple_queue_cache", 0x400, 0, + SLAB_HWCACHE_ALIGN, NULL); + + if (!maple_queue_cache) + goto cleanup_bothirqs; + + /* setup maple ports */ + for (i = 0; i < MAPLE_PORTS; i++) { + mdev[i] = maple_alloc_dev(i, 0); + if (!mdev[i]) { + while (i-- > 0) + maple_free_dev(mdev[i]); + goto cleanup_cache; + } + mdev[i]->registered = 0; + mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; + mdev[i]->mq->length = 0; + maple_attach_driver(mdev[i]); + maple_add_packet(mdev[i]->mq); + subdevice_map[i] = 0; + } + + /* setup maplebus hardware */ + maplebus_dma_reset(); + + /* initial detection */ + maple_send(); + + maple_pnp_time = jiffies; + + printk(KERN_INFO "Maple bus core now registered.\n"); + + return 0; + +cleanup_cache: + kmem_cache_destroy(maple_queue_cache); + +cleanup_bothirqs: + free_irq(HW_EVENT_VSYNC, 0); + +cleanup_irq: + free_irq(HW_EVENT_MAPLE_DMA, 0); + +cleanup_dma: + free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); + +cleanup_basic: + driver_unregister(&maple_dummy_driver.drv); + +cleanup_bus: + bus_unregister(&maple_bus_type); + +cleanup_device: + device_unregister(&maple_bus); + +cleanup: + printk(KERN_INFO "Maple bus registration failed\n"); + return retval; +} + +subsys_initcall(maple_bus_init); |
From: Adrian M. <lkm...@gm...> - 2007-09-15 19:32:38
|
The Maple bus is SEGA's proprietary serial bus for peripherals (keyboard, mouse, controller etc). The bus is capable of some (limited) hotplugging and operates at up to 2 M/bits. Drivers of one sort or another existed/exist for 2.4 and a rudimentary port, which didn't support the 2.6 device driver modei was also in existence. This driver - for the bus logic itself and for the keyboard (other drivers will follow) are based on the code and concepts of those old drivers but have lots of completely rewritten parts. I have the maplebus code a built in now as that seems the sane and rational way to handle something like that - you either want the bus or you don't. maplebus.c: adds the core bus support maple_keyb.c: adds the keyboard Signed off by Adrian McMenamin <ad...@mc...> |
From: shinkoi2005 <shi...@gm...> - 2007-09-15 02:00:57
|
> First of all, which board version are you using? It looks like your > patch is targeted for R2D-1. I think CF support is disabled for R2D-1 > just because of the problem your patch is trying to solve. I think R2D-PLUS has the same problem. Please see R2D-PLUS datasheet P.16. <http://documentation.renesas.com/eng/products/tool/rej10j1470_r0p751rlc0011rl_g.pdf> > Is the libata code working properly with 8 bit reads? Is this patch > all it takes to get CF working on R2D-1? At least, cf_ide_resources[](register map) is also incorrect with R2D-PLUS. Please check follow kernel which support P2D-PLUS and AT/PC arch's ATA register map. <http://www.superh-linux.org/archive/bsp/sh7751r_r2d/linux-2.6.14.4-R2D+_20060906.tar.bz2> R2D* board's ide register map is compatible without register access size. Here is the same patch... I can boot R2D-1 from IDE's rootfs with this patch. Signed-off-by: Aoi Shinkai <shi...@gm...> --- a/arch/sh/boards/renesas/rts7751r2d/setup.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) --- a/arch/sh/boards/renesas/rts7751r2d/setup.c +++ b/arch/sh/boards/renesas/rts7751r2d/setup.c @@ -45,12 +45,12 @@ static void __init voyagergx_serial_init(void) static struct resource cf_ide_resources[] = { [0] = { .start = PA_AREA5_IO + 0x1000, - .end = PA_AREA5_IO + 0x1000 + 0x08 - 1, + .end = PA_AREA5_IO + 0x1000 + 0x10 - 0x2, .flags = IORESOURCE_MEM, }, [1] = { .start = PA_AREA5_IO + 0x80c, - .end = PA_AREA5_IO + 0x80c + 0x16 - 1, + .end = PA_AREA5_IO + 0x80c, .flags = IORESOURCE_MEM, }, [2] = { @@ -141,19 +141,12 @@ static struct platform_device *rts7751r2d_devices[] __initdata = { &uart_device, &sm501_device, #endif + &cf_ide_device, &heartbeat_device, }; static int __init rts7751r2d_devices_setup(void) { - int ret; - - if (ctrl_inw(PA_BVERREG) == 0x10) { /* R2D-PLUS */ - ret = platform_device_register(&cf_ide_device); - if (ret) - return ret; - } - return platform_add_devices(rts7751r2d_devices, ARRAY_SIZE(rts7751r2d_devices)); } @@ -182,6 +175,36 @@ static void __init rts7751r2d_setup(char **cmdline_p) voyagergx_serial_init(); } +static inline unsigned char is_ide_ioaddr(unsigned long addr) { + if ((cf_ide_resources[0].start <= addr && + addr <= cf_ide_resources[0].end) || + (cf_ide_resources[1].start <= addr && + addr <= cf_ide_resources[1].end)) { + return 1; + } + return 0; +} + +void rts7751r2d_writeb(u8 b, void __iomem *addr) +{ + unsigned long tmp = (unsigned long __force)addr; + + if (is_ide_ioaddr(tmp)) + ctrl_outw((u16)b, tmp); + else + ctrl_outb(b, tmp); +} + +u8 rts7751r2d_readb(void __iomem *addr) +{ + unsigned long tmp = (unsigned long __force)addr; + + if (is_ide_ioaddr(tmp)) + return 0xff & ctrl_inw(tmp); + else + return ctrl_inb(tmp); +} + /* * The Machine Vector */ @@ -191,6 +214,8 @@ static struct sh_machine_vector mv_rts7751r2d __initmv = { .mv_init_irq = init_rts7751r2d_IRQ, .mv_irq_demux = rts7751r2d_irq_demux, + .mv_writeb = rts7751r2d_writeb, + .mv_readb = rts7751r2d_readb, #if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD) .mv_consistent_alloc = voyagergx_consistent_alloc, -- |
From: Adrian M. <ad...@ne...> - 2007-09-14 23:19:37
|
I have just turned on a whole host of debugging stuff in my kernel and now it won't boot because of the issue below - is this anything I need to formally file? [ 0.186328] ------------[ cut here ]------------ [ 0.191626] Badness at kernel/fork.c:1000 [ 0.196220] [ 0.197930] Pid : 0, Comm: swapper [ 0.203140] PC is at copy_process+0x13d2/0x1bc0 [ 0.208336] PC : 8c017012 SP : 8c2d9e78 SR : 40008101 TEA : 00000000 Not tainted [ 0.217417] R0 : 00000001 R1 : 00000000 R2 : 8c2beec8 R3 : 8c2d8000 [ 0.224983] R4 : 8c2f5a50 R5 : 8c28646c R6 : 8c2f5a50 R7 : 00000000 [ 0.232548] R8 : 00000000 R9 : 8c546000 R10 : 8c13c78e R11 : 8c545020 [ 0.240112] R12 : 00800b00 R13 : 8c545020 R14 : 8c2d9e78 [ 0.246191] MACH: 0000006c MACL: 00000000 GBR : 8c000000 PR : 8c017006 [ 0.253744] [ 0.253756] Call trace: [ 0.258348] [<8c013364>] sub_preempt_count+0x4/0xc0 [ 0.263969] [<8c233a12>] _spin_unlock_irq+0x32/0x80 [ 0.269595] [<8c02fb6e>] alloc_pid+0x1ee/0x3e0 [ 0.274721] [<8c01795c>] do_fork+0x5c/0x280 [ 0.279546] [<8c1334fc>] strlen+0x0/0x64 [ 0.284087] [<8c03d860>] trace_hardirqs_off+0x0/0xa0 [ 0.289812] [<8c003be8>] kernel_thread+0x48/0x80 [ 0.295128] [<8c1334fc>] strlen+0x0/0x64 [ 0.299654] [<8c2e1300>] __alloc_bootmem+0x0/0x60 [ 0.305068] [<8c2da4a0>] kernel_init+0x0/0x320 [ 0.310191] [<8c003ba0>] kernel_thread+0x0/0x80 [ 0.315410] [<8c2da4a0>] kernel_init+0x0/0x320 [ 0.320537] [<8c003900>] kernel_thread_helper+0x0/0x20 [ 0.326449] [<8c22ec52>] rest_init+0x12/0xa0 [ 0.331377] [<8c003ba0>] kernel_thread+0x0/0x80 [ 0.336590] [<8c2dacb4>] start_kernel+0x3d4/0x6a0 [ 0.342010] [<8c00202a>] _stext+0x2a/0x60 [ 0.346625] [ 0.348334] INFO: lockdep is turned off. |