brintos

brintos / linux-shallow public Read only

0
0
Text · 21.3 KiB · 6dc0549 Raw
889 lines · c
1/*2 * Core maple bus functionality3 *4 *  Copyright (C) 2007 - 2009 Adrian McMenamin5 *  Copyright (C) 2001 - 2008 Paul Mundt6 *  Copyright (C) 2000 - 2001 YAEGASHI Takeshi7 *  Copyright (C) 2001 M. R. Brown8 *9 * This file is subject to the terms and conditions of the GNU General Public10 * License.  See the file "COPYING" in the main directory of this archive11 * for more details.12 */13#include <linux/init.h>14#include <linux/kernel.h>15#include <linux/device.h>16#include <linux/interrupt.h>17#include <linux/list.h>18#include <linux/io.h>19#include <linux/slab.h>20#include <linux/maple.h>21#include <linux/dma-mapping.h>22#include <linux/delay.h>23#include <linux/module.h>24#include <asm/cacheflush.h>25#include <asm/dma.h>26#include <asm/io.h>27#include <mach/dma.h>28#include <mach/sysasic.h>29 30MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");31MODULE_DESCRIPTION("Maple bus driver for Dreamcast");32MODULE_LICENSE("GPL v2");33 34static void maple_dma_handler(struct work_struct *work);35static void maple_vblank_handler(struct work_struct *work);36 37static DECLARE_WORK(maple_dma_process, maple_dma_handler);38static DECLARE_WORK(maple_vblank_process, maple_vblank_handler);39 40static LIST_HEAD(maple_waitq);41static LIST_HEAD(maple_sentq);42 43/* mutex to protect queue of waiting packets */44static DEFINE_MUTEX(maple_wlist_lock);45 46static struct maple_driver maple_unsupported_device;47static struct device maple_bus;48static int subdevice_map[MAPLE_PORTS];49static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;50static unsigned long maple_pnp_time;51static int started, scanning, fullscan;52static struct kmem_cache *maple_queue_cache;53 54struct maple_device_specify {55	int port;56	int unit;57};58 59static bool checked[MAPLE_PORTS];60static bool empty[MAPLE_PORTS];61static struct maple_device *baseunits[MAPLE_PORTS];62static const struct bus_type maple_bus_type;63 64/**65 * maple_driver_register - register a maple driver66 * @drv: maple driver to be registered.67 *68 * Registers the passed in @drv, while updating the bus type.69 * Devices with matching function IDs will be automatically probed.70 */71int maple_driver_register(struct maple_driver *drv)72{73	if (!drv)74		return -EINVAL;75 76	drv->drv.bus = &maple_bus_type;77 78	return driver_register(&drv->drv);79}80EXPORT_SYMBOL_GPL(maple_driver_register);81 82/**83 * maple_driver_unregister - unregister a maple driver.84 * @drv: maple driver to unregister.85 *86 * Cleans up after maple_driver_register(). To be invoked in the exit87 * path of any module drivers.88 */89void maple_driver_unregister(struct maple_driver *drv)90{91	driver_unregister(&drv->drv);92}93EXPORT_SYMBOL_GPL(maple_driver_unregister);94 95/* set hardware registers to enable next round of dma */96static void maple_dma_reset(void)97{98	__raw_writel(MAPLE_MAGIC, MAPLE_RESET);99	/* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */100	__raw_writel(1, MAPLE_TRIGTYPE);101	/*102	* Maple system register103	* bits 31 - 16	timeout in units of 20nsec104	* bit 12	hard trigger - set 0 to keep responding to VBLANK105	* bits 9 - 8	set 00 for 2 Mbps, 01 for 1 Mbps106	* bits 3 - 0	delay (in 1.3ms) between VBLANK and start of DMA107	* max delay is 11108	*/109	__raw_writel(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);110	__raw_writel(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR);111	__raw_writel(1, MAPLE_ENABLE);112}113 114/**115 * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND116 * @dev: device responding117 * @callback: handler callback118 * @interval: interval in jiffies between callbacks119 * @function: the function code for the device120 */121void maple_getcond_callback(struct maple_device *dev,122			void (*callback) (struct mapleq *mq),123			unsigned long interval, unsigned long function)124{125	dev->callback = callback;126	dev->interval = interval;127	dev->function = cpu_to_be32(function);128	dev->when = jiffies;129}130EXPORT_SYMBOL_GPL(maple_getcond_callback);131 132static int maple_dma_done(void)133{134	return (__raw_readl(MAPLE_STATE) & 1) == 0;135}136 137static void maple_release_device(struct device *dev)138{139	struct maple_device *mdev;140	struct mapleq *mq;141 142	mdev = to_maple_dev(dev);143	mq = mdev->mq;144	kmem_cache_free(maple_queue_cache, mq->recvbuf);145	kfree(mq);146	kfree(mdev);147}148 149/**150 * maple_add_packet - add a single instruction to the maple bus queue151 * @mdev: maple device152 * @function: function on device being queried153 * @command: maple command to add154 * @length: length of command string (in 32 bit words)155 * @data: remainder of command string156 */157int maple_add_packet(struct maple_device *mdev, u32 function, u32 command,158	size_t length, void *data)159{160	int ret = 0;161	void *sendbuf = NULL;162 163	if (length) {164		sendbuf = kcalloc(length, 4, GFP_KERNEL);165		if (!sendbuf) {166			ret = -ENOMEM;167			goto out;168		}169		((__be32 *)sendbuf)[0] = cpu_to_be32(function);170	}171 172	mdev->mq->command = command;173	mdev->mq->length = length;174	if (length > 1)175		memcpy(sendbuf + 4, data, (length - 1) * 4);176	mdev->mq->sendbuf = sendbuf;177 178	mutex_lock(&maple_wlist_lock);179	list_add_tail(&mdev->mq->list, &maple_waitq);180	mutex_unlock(&maple_wlist_lock);181out:182	return ret;183}184EXPORT_SYMBOL_GPL(maple_add_packet);185 186static struct mapleq *maple_allocq(struct maple_device *mdev)187{188	struct mapleq *mq;189 190	mq = kzalloc(sizeof(*mq), GFP_KERNEL);191	if (!mq)192		goto failed_nomem;193 194	INIT_LIST_HEAD(&mq->list);195	mq->dev = mdev;196	mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);197	if (!mq->recvbuf)198		goto failed_p2;199	mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]);200 201	return mq;202 203failed_p2:204	kfree(mq);205failed_nomem:206	dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n",207		mdev->port, mdev->unit);208	return NULL;209}210 211static struct maple_device *maple_alloc_dev(int port, int unit)212{213	struct maple_device *mdev;214 215	/* zero this out to avoid kobj subsystem216	* thinking it has already been registered */217 218	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);219	if (!mdev)220		return NULL;221 222	mdev->port = port;223	mdev->unit = unit;224 225	mdev->mq = maple_allocq(mdev);226 227	if (!mdev->mq) {228		kfree(mdev);229		return NULL;230	}231	mdev->dev.bus = &maple_bus_type;232	mdev->dev.parent = &maple_bus;233	init_waitqueue_head(&mdev->maple_wait);234	return mdev;235}236 237static void maple_free_dev(struct maple_device *mdev)238{239	kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf);240	kfree(mdev->mq);241	kfree(mdev);242}243 244/* process the command queue into a maple command block245 * terminating command has bit 32 of first long set to 0246 */247static void maple_build_block(struct mapleq *mq)248{249	int port, unit, from, to, len;250	unsigned long *lsendbuf = mq->sendbuf;251 252	port = mq->dev->port & 3;253	unit = mq->dev->unit;254	len = mq->length;255	from = port << 6;256	to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20);257 258	*maple_lastptr &= 0x7fffffff;259	maple_lastptr = maple_sendptr;260 261	*maple_sendptr++ = (port << 16) | len | 0x80000000;262	*maple_sendptr++ = virt_to_phys(mq->recvbuf->buf);263	*maple_sendptr++ =264	    mq->command | (to << 8) | (from << 16) | (len << 24);265	while (len-- > 0)266		*maple_sendptr++ = *lsendbuf++;267}268 269/* build up command queue */270static void maple_send(void)271{272	int i, maple_packets = 0;273	struct mapleq *mq, *nmq;274 275	if (!maple_dma_done())276		return;277 278	/* disable DMA */279	__raw_writel(0, MAPLE_ENABLE);280 281	if (!list_empty(&maple_sentq))282		goto finish;283 284	mutex_lock(&maple_wlist_lock);285	if (list_empty(&maple_waitq)) {286		mutex_unlock(&maple_wlist_lock);287		goto finish;288	}289 290	maple_lastptr = maple_sendbuf;291	maple_sendptr = maple_sendbuf;292 293	list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {294		maple_build_block(mq);295		list_del_init(&mq->list);296		list_add_tail(&mq->list, &maple_sentq);297		if (maple_packets++ > MAPLE_MAXPACKETS)298			break;299	}300	mutex_unlock(&maple_wlist_lock);301	if (maple_packets > 0) {302		for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++)303			__flush_purge_region(maple_sendbuf + i * PAGE_SIZE,304					PAGE_SIZE);305	}306 307finish:308	maple_dma_reset();309}310 311/* check if there is a driver registered likely to match this device */312static int maple_check_matching_driver(struct device_driver *driver,313					void *devptr)314{315	struct maple_driver *maple_drv;316	struct maple_device *mdev;317 318	mdev = devptr;319	maple_drv = to_maple_driver(driver);320	if (mdev->devinfo.function & cpu_to_be32(maple_drv->function))321		return 1;322	return 0;323}324 325static void maple_detach_driver(struct maple_device *mdev)326{327	device_unregister(&mdev->dev);328}329 330/* process initial MAPLE_COMMAND_DEVINFO for each device or port */331static void maple_attach_driver(struct maple_device *mdev)332{333	char *p, *recvbuf;334	unsigned long function;335	int matched, error;336 337	recvbuf = mdev->mq->recvbuf->buf;338	/* copy the data as individual elements in339	* case of memory optimisation */340	memcpy(&mdev->devinfo.function, recvbuf + 4, 4);341	memcpy(&mdev->devinfo.function_data[0], recvbuf + 8, 12);342	memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1);343	memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1);344	memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30);345	memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2);346	memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2);347	memcpy(mdev->product_name, mdev->devinfo.product_name, 30);348	mdev->product_name[30] = '\0';349	memcpy(mdev->product_licence, mdev->devinfo.product_licence, 60);350	mdev->product_licence[60] = '\0';351 352	for (p = mdev->product_name + 29; mdev->product_name <= p; p--)353		if (*p == ' ')354			*p = '\0';355		else356			break;357	for (p = mdev->product_licence + 59; mdev->product_licence <= p; p--)358		if (*p == ' ')359			*p = '\0';360		else361			break;362 363	function = be32_to_cpu(mdev->devinfo.function);364 365	dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n",366		mdev->product_name, function, mdev->port, mdev->unit);367 368	if (function > 0x200) {369		/* Do this silently - as not a real device */370		function = 0;371		mdev->driver = &maple_unsupported_device;372		dev_set_name(&mdev->dev, "%d:0.port", mdev->port);373	} else {374		matched =375			bus_for_each_drv(&maple_bus_type, NULL, mdev,376				maple_check_matching_driver);377 378		if (matched == 0) {379			/* Driver does not exist yet */380			dev_info(&mdev->dev, "no driver found\n");381			mdev->driver = &maple_unsupported_device;382		}383		dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port,384			     mdev->unit, function);385	}386 387	mdev->function = function;388	mdev->dev.release = &maple_release_device;389 390	atomic_set(&mdev->busy, 0);391	error = device_register(&mdev->dev);392	if (error) {393		dev_warn(&mdev->dev, "could not register device at"394			" (%d, %d), with error 0x%X\n", mdev->unit,395			mdev->port, error);396		maple_free_dev(mdev);397		mdev = NULL;398		return;399	}400}401 402/*403 * if device has been registered for the given404 * port and unit then return 1 - allows identification405 * of which devices need to be attached or detached406 */407static int check_maple_device(struct device *device, void *portptr)408{409	struct maple_device_specify *ds;410	struct maple_device *mdev;411 412	ds = portptr;413	mdev = to_maple_dev(device);414	if (mdev->port == ds->port && mdev->unit == ds->unit)415		return 1;416	return 0;417}418 419static int setup_maple_commands(struct device *device, void *ignored)420{421	int add;422	struct maple_device *mdev = to_maple_dev(device);423	if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 &&424		time_after(jiffies, mdev->when)) {425		/* bounce if we cannot add */426		add = maple_add_packet(mdev,427			be32_to_cpu(mdev->devinfo.function),428			MAPLE_COMMAND_GETCOND, 1, NULL);429		if (!add)430			mdev->when = jiffies + mdev->interval;431	} else {432		if (time_after(jiffies, maple_pnp_time))433			/* Ensure we don't have block reads and devinfo434			* calls interfering with one another - so flag the435			* device as busy */436			if (atomic_read(&mdev->busy) == 0) {437				atomic_set(&mdev->busy, 1);438				maple_add_packet(mdev, 0,439					MAPLE_COMMAND_DEVINFO, 0, NULL);440			}441	}442	return 0;443}444 445/* VBLANK bottom half - implemented via workqueue */446static void maple_vblank_handler(struct work_struct *work)447{448	int x, locking;449	struct maple_device *mdev;450 451	if (!maple_dma_done())452		return;453 454	__raw_writel(0, MAPLE_ENABLE);455 456	if (!list_empty(&maple_sentq))457		goto finish;458 459	/*460	* Set up essential commands - to fetch data and461	* check devices are still present462	*/463	bus_for_each_dev(&maple_bus_type, NULL, NULL,464		setup_maple_commands);465 466	if (time_after(jiffies, maple_pnp_time)) {467		/*468		* Scan the empty ports - bus is flakey and may have469		* mis-reported emptyness470		*/471		for (x = 0; x < MAPLE_PORTS; x++) {472			if (checked[x] && empty[x]) {473				mdev = baseunits[x];474				if (!mdev)475					break;476				atomic_set(&mdev->busy, 1);477				locking = maple_add_packet(mdev, 0,478					MAPLE_COMMAND_DEVINFO, 0, NULL);479				if (!locking)480					break;481				}482			}483 484		maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;485	}486 487finish:488	maple_send();489}490 491/* handle devices added via hotplugs - placing them on queue for DEVINFO */492static void maple_map_subunits(struct maple_device *mdev, int submask)493{494	int retval, k, devcheck;495	struct maple_device *mdev_add;496	struct maple_device_specify ds;497 498	ds.port = mdev->port;499	for (k = 0; k < 5; k++) {500		ds.unit = k + 1;501		retval =502		    bus_for_each_dev(&maple_bus_type, NULL, &ds,503				     check_maple_device);504		if (retval) {505			submask = submask >> 1;506			continue;507		}508		devcheck = submask & 0x01;509		if (devcheck) {510			mdev_add = maple_alloc_dev(mdev->port, k + 1);511			if (!mdev_add)512				return;513			atomic_set(&mdev_add->busy, 1);514			maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO,515				0, NULL);516			/* mark that we are checking sub devices */517			scanning = 1;518		}519		submask = submask >> 1;520	}521}522 523/* mark a device as removed */524static void maple_clean_submap(struct maple_device *mdev)525{526	int killbit;527 528	killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20);529	killbit = ~killbit;530	killbit &= 0xFF;531	subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit;532}533 534/* handle empty port or hotplug removal */535static void maple_response_none(struct maple_device *mdev)536{537	maple_clean_submap(mdev);538 539	if (likely(mdev->unit != 0)) {540		/*541		* Block devices play up542		* and give the impression they have543		* been removed even when still in place or544		* trip the mtd layer when they have545		* really gone - this code traps that eventuality546		* and ensures we aren't overloaded with useless547		* error messages548		*/549		if (mdev->can_unload) {550			if (!mdev->can_unload(mdev)) {551				atomic_set(&mdev->busy, 2);552				wake_up(&mdev->maple_wait);553				return;554			}555		}556 557		dev_info(&mdev->dev, "detaching device at (%d, %d)\n",558			mdev->port, mdev->unit);559		maple_detach_driver(mdev);560		return;561	} else {562		if (!started || !fullscan) {563			if (checked[mdev->port] == false) {564				checked[mdev->port] = true;565				empty[mdev->port] = true;566				dev_info(&mdev->dev, "no devices"567					" to port %d\n", mdev->port);568			}569			return;570		}571	}572	/* Some hardware devices generate false detach messages on unit 0 */573	atomic_set(&mdev->busy, 0);574}575 576/* preprocess hotplugs or scans */577static void maple_response_devinfo(struct maple_device *mdev,578				   char *recvbuf)579{580	char submask;581	if (!started || (scanning == 2) || !fullscan) {582		if ((mdev->unit == 0) && (checked[mdev->port] == false)) {583			checked[mdev->port] = true;584			maple_attach_driver(mdev);585		} else {586			if (mdev->unit != 0)587				maple_attach_driver(mdev);588			if (mdev->unit == 0) {589				empty[mdev->port] = false;590				maple_attach_driver(mdev);591			}592		}593	}594	if (mdev->unit == 0) {595		submask = recvbuf[2] & 0x1F;596		if (submask ^ subdevice_map[mdev->port]) {597			maple_map_subunits(mdev, submask);598			subdevice_map[mdev->port] = submask;599		}600	}601}602 603static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf)604{605	if (mdev->fileerr_handler) {606		mdev->fileerr_handler(mdev, recvbuf);607		return;608	} else609		dev_warn(&mdev->dev, "device at (%d, %d) reports"610			"file error 0x%X\n", mdev->port, mdev->unit,611			((int *)recvbuf)[1]);612}613 614static void maple_port_rescan(void)615{616	int i;617	struct maple_device *mdev;618 619	fullscan = 1;620	for (i = 0; i < MAPLE_PORTS; i++) {621		if (checked[i] == false) {622			fullscan = 0;623			mdev = baseunits[i];624			maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO,625				0, NULL);626		}627	}628}629 630/* maple dma end bottom half - implemented via workqueue */631static void maple_dma_handler(struct work_struct *work)632{633	struct mapleq *mq, *nmq;634	struct maple_device *mdev;635	char *recvbuf;636	enum maple_code code;637 638	if (!maple_dma_done())639		return;640	__raw_writel(0, MAPLE_ENABLE);641	if (!list_empty(&maple_sentq)) {642		list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {643			mdev = mq->dev;644			recvbuf = mq->recvbuf->buf;645			__flush_invalidate_region(sh_cacheop_vaddr(recvbuf),646					0x400);647			code = recvbuf[0];648			kfree(mq->sendbuf);649			list_del_init(&mq->list);650			switch (code) {651			case MAPLE_RESPONSE_NONE:652				maple_response_none(mdev);653				break;654 655			case MAPLE_RESPONSE_DEVINFO:656				maple_response_devinfo(mdev, recvbuf);657				atomic_set(&mdev->busy, 0);658				break;659 660			case MAPLE_RESPONSE_DATATRF:661				if (mdev->callback)662					mdev->callback(mq);663				atomic_set(&mdev->busy, 0);664				wake_up(&mdev->maple_wait);665				break;666 667			case MAPLE_RESPONSE_FILEERR:668				maple_response_fileerr(mdev, recvbuf);669				atomic_set(&mdev->busy, 0);670				wake_up(&mdev->maple_wait);671				break;672 673			case MAPLE_RESPONSE_AGAIN:674			case MAPLE_RESPONSE_BADCMD:675			case MAPLE_RESPONSE_BADFUNC:676				dev_warn(&mdev->dev, "non-fatal error"677					" 0x%X at (%d, %d)\n", code,678					mdev->port, mdev->unit);679				atomic_set(&mdev->busy, 0);680				break;681 682			case MAPLE_RESPONSE_ALLINFO:683				dev_notice(&mdev->dev, "extended"684				" device information request for (%d, %d)"685				" but call is not supported\n", mdev->port,686				mdev->unit);687				atomic_set(&mdev->busy, 0);688				break;689 690			case MAPLE_RESPONSE_OK:691				atomic_set(&mdev->busy, 0);692				wake_up(&mdev->maple_wait);693				break;694 695			default:696				break;697			}698		}699		/* if scanning is 1 then we have subdevices to check */700		if (scanning == 1) {701			maple_send();702			scanning = 2;703		} else704			scanning = 0;705		/*check if we have actually tested all ports yet */706		if (!fullscan)707			maple_port_rescan();708		/* mark that we have been through the first scan */709		started = 1;710	}711	maple_send();712}713 714static irqreturn_t maple_dma_interrupt(int irq, void *dev_id)715{716	/* Load everything into the bottom half */717	schedule_work(&maple_dma_process);718	return IRQ_HANDLED;719}720 721static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id)722{723	schedule_work(&maple_vblank_process);724	return IRQ_HANDLED;725}726 727static int maple_set_dma_interrupt_handler(void)728{729	return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt,730		IRQF_SHARED, "maple bus DMA", &maple_unsupported_device);731}732 733static int maple_set_vblank_interrupt_handler(void)734{735	return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt,736		IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device);737}738 739static int maple_get_dma_buffer(void)740{741	maple_sendbuf =742	    (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,743				      MAPLE_DMA_PAGES);744	if (!maple_sendbuf)745		return -ENOMEM;746	return 0;747}748 749static int maple_match_bus_driver(struct device *devptr,750				  const struct device_driver *drvptr)751{752	const struct maple_driver *maple_drv = to_maple_driver(drvptr);753	struct maple_device *maple_dev = to_maple_dev(devptr);754 755	/* Trap empty port case */756	if (maple_dev->devinfo.function == 0xFFFFFFFF)757		return 0;758	else if (maple_dev->devinfo.function &759		 cpu_to_be32(maple_drv->function))760		return 1;761	return 0;762}763 764static void maple_bus_release(struct device *dev)765{766}767 768static struct maple_driver maple_unsupported_device = {769	.drv = {770		.name = "maple_unsupported_device",771		.bus = &maple_bus_type,772	},773};774/*775 * maple_bus_type - core maple bus structure776 */777static const struct bus_type maple_bus_type = {778	.name = "maple",779	.match = maple_match_bus_driver,780};781 782static struct device maple_bus = {783	.init_name = "maple",784	.release = maple_bus_release,785};786 787static int __init maple_bus_init(void)788{789	int retval, i;790	struct maple_device *mdev[MAPLE_PORTS];791 792	__raw_writel(0, MAPLE_ENABLE);793 794	retval = device_register(&maple_bus);795	if (retval)796		goto cleanup;797 798	retval = bus_register(&maple_bus_type);799	if (retval)800		goto cleanup_device;801 802	retval = driver_register(&maple_unsupported_device.drv);803	if (retval)804		goto cleanup_bus;805 806	/* allocate memory for maple bus dma */807	retval = maple_get_dma_buffer();808	if (retval) {809		dev_err(&maple_bus, "failed to allocate DMA buffers\n");810		goto cleanup_basic;811	}812 813	/* set up DMA interrupt handler */814	retval = maple_set_dma_interrupt_handler();815	if (retval) {816		dev_err(&maple_bus, "bus failed to grab maple "817			"DMA IRQ\n");818		goto cleanup_dma;819	}820 821	/* set up VBLANK interrupt handler */822	retval = maple_set_vblank_interrupt_handler();823	if (retval) {824		dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n");825		goto cleanup_irq;826	}827 828	maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN);829 830	if (!maple_queue_cache) {831		retval = -ENOMEM;832		goto cleanup_bothirqs;833	}834 835	INIT_LIST_HEAD(&maple_waitq);836	INIT_LIST_HEAD(&maple_sentq);837 838	/* setup maple ports */839	for (i = 0; i < MAPLE_PORTS; i++) {840		checked[i] = false;841		empty[i] = false;842		mdev[i] = maple_alloc_dev(i, 0);843		if (!mdev[i]) {844			while (i-- > 0)845				maple_free_dev(mdev[i]);846			retval = -ENOMEM;847			goto cleanup_cache;848		}849		baseunits[i] = mdev[i];850		atomic_set(&mdev[i]->busy, 1);851		maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL);852		subdevice_map[i] = 0;853	}854 855	maple_pnp_time = jiffies + HZ;856	/* prepare initial queue */857	maple_send();858	dev_info(&maple_bus, "bus core now registered\n");859 860	return 0;861 862cleanup_cache:863	kmem_cache_destroy(maple_queue_cache);864 865cleanup_bothirqs:866	free_irq(HW_EVENT_VSYNC, 0);867 868cleanup_irq:869	free_irq(HW_EVENT_MAPLE_DMA, 0);870 871cleanup_dma:872	free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);873 874cleanup_basic:875	driver_unregister(&maple_unsupported_device.drv);876 877cleanup_bus:878	bus_unregister(&maple_bus_type);879 880cleanup_device:881	device_unregister(&maple_bus);882 883cleanup:884	printk(KERN_ERR "Maple bus registration failed\n");885	return retval;886}887/* Push init to later to ensure hardware gets detected */888fs_initcall(maple_bus_init);889