diff options
author | Adrian McMenamin <adrian@mcmen.demon.co.uk> | 2009-02-27 02:07:32 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-02-27 02:07:32 -0500 |
commit | b233b28eac0cc37d07c2d007ea08c86c778c5af4 (patch) | |
tree | 636f91b57d675d1886d8b3ab4aca8d8488d65d90 | |
parent | 41480ae7a383dcffa497decdd97b3cb2caaa18ec (diff) |
sh: maple: Support block reads and writes.
This patch updates the maple bus to support asynchronous block reads
and writes as well as generally improving the quality of the code and
supporting concurrency (all needed to support the Dreamcast visual
memory unit - a driver will also be posted for that).
Changes in the bus driver necessitate some changes in the two maple bus
input drivers that are currently in mainline.
As well as supporting block reads and writes this code clean up removes
some poor handling of locks, uses an atomic status variable to serialise
access to devices and more robusly handles the general performance
problems of the bus.
Signed-off-by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | drivers/input/joystick/maplecontrol.c | 4 | ||||
-rw-r--r-- | drivers/input/keyboard/maple_keyb.c | 37 | ||||
-rw-r--r-- | drivers/sh/maple/maple.c | 463 | ||||
-rw-r--r-- | include/linux/maple.h | 62 |
4 files changed, 300 insertions, 266 deletions
diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c index e50047bfe938..77cfde571bd9 100644 --- a/drivers/input/joystick/maplecontrol.c +++ b/drivers/input/joystick/maplecontrol.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Based on drivers/usb/iforce.c | 3 | * Based on drivers/usb/iforce.c |
4 | * | 4 | * |
5 | * Copyright Yaegashi Takeshi, 2001 | 5 | * Copyright Yaegashi Takeshi, 2001 |
6 | * Adrian McMenamin, 2008 | 6 | * Adrian McMenamin, 2008 - 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
@@ -29,7 +29,7 @@ static void dc_pad_callback(struct mapleq *mq) | |||
29 | struct maple_device *mapledev = mq->dev; | 29 | struct maple_device *mapledev = mq->dev; |
30 | struct dc_pad *pad = maple_get_drvdata(mapledev); | 30 | struct dc_pad *pad = maple_get_drvdata(mapledev); |
31 | struct input_dev *dev = pad->dev; | 31 | struct input_dev *dev = pad->dev; |
32 | unsigned char *res = mq->recvbuf; | 32 | unsigned char *res = mq->recvbuf->buf; |
33 | 33 | ||
34 | buttons = ~le16_to_cpup((__le16 *)(res + 8)); | 34 | buttons = ~le16_to_cpup((__le16 *)(res + 8)); |
35 | 35 | ||
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 22f17a593be7..5aa2361aef95 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * SEGA Dreamcast keyboard driver | 2 | * SEGA Dreamcast keyboard driver |
3 | * Based on drivers/usb/usbkbd.c | 3 | * Based on drivers/usb/usbkbd.c |
4 | * Copyright YAEGASHI Takeshi, 2001 | 4 | * Copyright (c) YAEGASHI Takeshi, 2001 |
5 | * Porting to 2.6 Copyright Adrian McMenamin, 2007, 2008 | 5 | * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009 |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -33,7 +33,7 @@ static DEFINE_MUTEX(maple_keyb_mutex); | |||
33 | 33 | ||
34 | #define NR_SCANCODES 256 | 34 | #define NR_SCANCODES 256 |
35 | 35 | ||
36 | MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin"); | 36 | MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk"); |
37 | MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); | 37 | MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); |
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | 39 | ||
@@ -115,7 +115,7 @@ static void dc_scan_kbd(struct dc_kbd *kbd) | |||
115 | input_event(dev, EV_MSC, MSC_SCAN, code); | 115 | input_event(dev, EV_MSC, MSC_SCAN, code); |
116 | input_report_key(dev, keycode, 0); | 116 | input_report_key(dev, keycode, 0); |
117 | } else | 117 | } else |
118 | printk(KERN_DEBUG "maple_keyb: " | 118 | dev_dbg(&dev->dev, |
119 | "Unknown key (scancode %#x) released.", | 119 | "Unknown key (scancode %#x) released.", |
120 | code); | 120 | code); |
121 | } | 121 | } |
@@ -127,7 +127,7 @@ static void dc_scan_kbd(struct dc_kbd *kbd) | |||
127 | input_event(dev, EV_MSC, MSC_SCAN, code); | 127 | input_event(dev, EV_MSC, MSC_SCAN, code); |
128 | input_report_key(dev, keycode, 1); | 128 | input_report_key(dev, keycode, 1); |
129 | } else | 129 | } else |
130 | printk(KERN_DEBUG "maple_keyb: " | 130 | dev_dbg(&dev->dev, |
131 | "Unknown key (scancode %#x) pressed.", | 131 | "Unknown key (scancode %#x) pressed.", |
132 | code); | 132 | code); |
133 | } | 133 | } |
@@ -140,7 +140,7 @@ static void dc_kbd_callback(struct mapleq *mq) | |||
140 | { | 140 | { |
141 | struct maple_device *mapledev = mq->dev; | 141 | struct maple_device *mapledev = mq->dev; |
142 | struct dc_kbd *kbd = maple_get_drvdata(mapledev); | 142 | struct dc_kbd *kbd = maple_get_drvdata(mapledev); |
143 | unsigned long *buf = mq->recvbuf; | 143 | unsigned long *buf = (unsigned long *)(mq->recvbuf->buf); |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * We should always get the lock because the only | 146 | * We should always get the lock because the only |
@@ -159,22 +159,27 @@ static void dc_kbd_callback(struct mapleq *mq) | |||
159 | 159 | ||
160 | static int probe_maple_kbd(struct device *dev) | 160 | static int probe_maple_kbd(struct device *dev) |
161 | { | 161 | { |
162 | struct maple_device *mdev = to_maple_dev(dev); | 162 | struct maple_device *mdev; |
163 | struct maple_driver *mdrv = to_maple_driver(dev->driver); | 163 | struct maple_driver *mdrv; |
164 | int i, error; | 164 | int i, error; |
165 | struct dc_kbd *kbd; | 165 | struct dc_kbd *kbd; |
166 | struct input_dev *idev; | 166 | struct input_dev *idev; |
167 | 167 | ||
168 | if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) | 168 | mdev = to_maple_dev(dev); |
169 | return -EINVAL; | 169 | mdrv = to_maple_driver(dev->driver); |
170 | 170 | ||
171 | kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); | 171 | kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); |
172 | idev = input_allocate_device(); | 172 | if (!kbd) { |
173 | if (!kbd || !idev) { | ||
174 | error = -ENOMEM; | 173 | error = -ENOMEM; |
175 | goto fail; | 174 | goto fail; |
176 | } | 175 | } |
177 | 176 | ||
177 | idev = input_allocate_device(); | ||
178 | if (!idev) { | ||
179 | error = -ENOMEM; | ||
180 | goto fail_idev_alloc; | ||
181 | } | ||
182 | |||
178 | kbd->dev = idev; | 183 | kbd->dev = idev; |
179 | memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); | 184 | memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); |
180 | 185 | ||
@@ -195,7 +200,7 @@ static int probe_maple_kbd(struct device *dev) | |||
195 | 200 | ||
196 | error = input_register_device(idev); | 201 | error = input_register_device(idev); |
197 | if (error) | 202 | if (error) |
198 | goto fail; | 203 | goto fail_register; |
199 | 204 | ||
200 | /* Maple polling is locked to VBLANK - which may be just 50/s */ | 205 | /* Maple polling is locked to VBLANK - which may be just 50/s */ |
201 | maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, | 206 | maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, |
@@ -207,10 +212,12 @@ static int probe_maple_kbd(struct device *dev) | |||
207 | 212 | ||
208 | return error; | 213 | return error; |
209 | 214 | ||
210 | fail: | 215 | fail_register: |
216 | maple_set_drvdata(mdev, NULL); | ||
211 | input_free_device(idev); | 217 | input_free_device(idev); |
218 | fail_idev_alloc: | ||
212 | kfree(kbd); | 219 | kfree(kbd); |
213 | maple_set_drvdata(mdev, NULL); | 220 | fail: |
214 | return error; | 221 | return error; |
215 | } | 222 | } |
216 | 223 | ||
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 63f0de29aa14..4054fe93d6e4 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c | |||
@@ -1,16 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Core maple bus functionality | 2 | * Core maple bus functionality |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Adrian McMenamin | 4 | * Copyright (C) 2007 - 2009 Adrian McMenamin |
5 | * Copyright (C) 2001 - 2008 Paul Mundt | 5 | * Copyright (C) 2001 - 2008 Paul Mundt |
6 | * | 6 | * Copyright (C) 2000 - 2001 YAEGASHI Takeshi |
7 | * Based on 2.4 code by: | ||
8 | * | ||
9 | * Copyright (C) 2000-2001 YAEGASHI Takeshi | ||
10 | * Copyright (C) 2001 M. R. Brown | 7 | * Copyright (C) 2001 M. R. Brown |
11 | * Copyright (C) 2001 Paul Mundt | ||
12 | * | ||
13 | * and others. | ||
14 | * | 8 | * |
15 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * License. See the file "COPYING" in the main directory of this archive | 10 | * License. See the file "COPYING" in the main directory of this archive |
@@ -32,7 +26,7 @@ | |||
32 | #include <mach/dma.h> | 26 | #include <mach/dma.h> |
33 | #include <mach/sysasic.h> | 27 | #include <mach/sysasic.h> |
34 | 28 | ||
35 | MODULE_AUTHOR("Yaegashi Takeshi, Paul Mundt, M. R. Brown, Adrian McMenamin"); | 29 | MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); |
36 | MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); | 30 | MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); |
37 | MODULE_LICENSE("GPL v2"); | 31 | MODULE_LICENSE("GPL v2"); |
38 | MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); | 32 | MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); |
@@ -49,7 +43,7 @@ static LIST_HEAD(maple_sentq); | |||
49 | /* mutex to protect queue of waiting packets */ | 43 | /* mutex to protect queue of waiting packets */ |
50 | static DEFINE_MUTEX(maple_wlist_lock); | 44 | static DEFINE_MUTEX(maple_wlist_lock); |
51 | 45 | ||
52 | static struct maple_driver maple_dummy_driver; | 46 | static struct maple_driver maple_unsupported_device; |
53 | static struct device maple_bus; | 47 | static struct device maple_bus; |
54 | static int subdevice_map[MAPLE_PORTS]; | 48 | static int subdevice_map[MAPLE_PORTS]; |
55 | static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; | 49 | static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; |
@@ -62,8 +56,9 @@ struct maple_device_specify { | |||
62 | int unit; | 56 | int unit; |
63 | }; | 57 | }; |
64 | 58 | ||
65 | static bool checked[4]; | 59 | static bool checked[MAPLE_PORTS]; |
66 | static struct maple_device *baseunits[4]; | 60 | static bool empty[MAPLE_PORTS]; |
61 | static struct maple_device *baseunits[MAPLE_PORTS]; | ||
67 | 62 | ||
68 | /** | 63 | /** |
69 | * maple_driver_register - register a maple driver | 64 | * maple_driver_register - register a maple driver |
@@ -97,12 +92,20 @@ void maple_driver_unregister(struct maple_driver *drv) | |||
97 | EXPORT_SYMBOL_GPL(maple_driver_unregister); | 92 | EXPORT_SYMBOL_GPL(maple_driver_unregister); |
98 | 93 | ||
99 | /* set hardware registers to enable next round of dma */ | 94 | /* set hardware registers to enable next round of dma */ |
100 | static void maplebus_dma_reset(void) | 95 | static void maple_dma_reset(void) |
101 | { | 96 | { |
102 | ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); | 97 | ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); |
103 | /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ | 98 | /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ |
104 | ctrl_outl(1, MAPLE_TRIGTYPE); | 99 | ctrl_outl(1, MAPLE_TRIGTYPE); |
105 | ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); | 100 | /* |
101 | * Maple system register | ||
102 | * bits 31 - 16 timeout in units of 20nsec | ||
103 | * bit 12 hard trigger - set 0 to keep responding to VBLANK | ||
104 | * bits 9 - 8 set 00 for 2 Mbps, 01 for 1 Mbps | ||
105 | * bits 3 - 0 delay (in 1.3ms) between VBLANK and start of DMA | ||
106 | * max delay is 11 | ||
107 | */ | ||
108 | ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED); | ||
106 | ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); | 109 | ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); |
107 | ctrl_outl(1, MAPLE_ENABLE); | 110 | ctrl_outl(1, MAPLE_ENABLE); |
108 | } | 111 | } |
@@ -134,21 +137,16 @@ static void maple_release_device(struct device *dev) | |||
134 | { | 137 | { |
135 | struct maple_device *mdev; | 138 | struct maple_device *mdev; |
136 | struct mapleq *mq; | 139 | struct mapleq *mq; |
137 | if (!dev) | 140 | |
138 | return; | ||
139 | mdev = to_maple_dev(dev); | 141 | mdev = to_maple_dev(dev); |
140 | mq = mdev->mq; | 142 | mq = mdev->mq; |
141 | if (mq) { | 143 | kmem_cache_free(maple_queue_cache, mq->recvbuf); |
142 | if (mq->recvbufdcsp) | 144 | kfree(mq); |
143 | kmem_cache_free(maple_queue_cache, mq->recvbufdcsp); | ||
144 | kfree(mq); | ||
145 | mq = NULL; | ||
146 | } | ||
147 | kfree(mdev); | 145 | kfree(mdev); |
148 | } | 146 | } |
149 | 147 | ||
150 | /** | 148 | /** |
151 | * maple_add_packet - add a single instruction to the queue | 149 | * maple_add_packet - add a single instruction to the maple bus queue |
152 | * @mdev: maple device | 150 | * @mdev: maple device |
153 | * @function: function on device being queried | 151 | * @function: function on device being queried |
154 | * @command: maple command to add | 152 | * @command: maple command to add |
@@ -158,68 +156,12 @@ static void maple_release_device(struct device *dev) | |||
158 | int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, | 156 | int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, |
159 | size_t length, void *data) | 157 | size_t length, void *data) |
160 | { | 158 | { |
161 | int locking, ret = 0; | 159 | int ret = 0; |
162 | void *sendbuf = NULL; | 160 | void *sendbuf = NULL; |
163 | 161 | ||
164 | mutex_lock(&maple_wlist_lock); | ||
165 | /* bounce if device already locked */ | ||
166 | locking = mutex_is_locked(&mdev->mq->mutex); | ||
167 | if (locking) { | ||
168 | ret = -EBUSY; | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | mutex_lock(&mdev->mq->mutex); | ||
173 | |||
174 | if (length) { | 162 | if (length) { |
175 | sendbuf = kmalloc(length * 4, GFP_KERNEL); | 163 | sendbuf = kzalloc(length * 4, GFP_KERNEL); |
176 | if (!sendbuf) { | 164 | if (!sendbuf) { |
177 | mutex_unlock(&mdev->mq->mutex); | ||
178 | ret = -ENOMEM; | ||
179 | goto out; | ||
180 | } | ||
181 | ((__be32 *)sendbuf)[0] = cpu_to_be32(function); | ||
182 | } | ||
183 | |||
184 | mdev->mq->command = command; | ||
185 | mdev->mq->length = length; | ||
186 | if (length > 1) | ||
187 | memcpy(sendbuf + 4, data, (length - 1) * 4); | ||
188 | mdev->mq->sendbuf = sendbuf; | ||
189 | |||
190 | list_add(&mdev->mq->list, &maple_waitq); | ||
191 | out: | ||
192 | mutex_unlock(&maple_wlist_lock); | ||
193 | return ret; | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(maple_add_packet); | ||
196 | |||
197 | /** | ||
198 | * maple_add_packet_sleeps - add a single instruction to the queue | ||
199 | * @mdev: maple device | ||
200 | * @function: function on device being queried | ||
201 | * @command: maple command to add | ||
202 | * @length: length of command string (in 32 bit words) | ||
203 | * @data: remainder of command string | ||
204 | * | ||
205 | * Same as maple_add_packet(), but waits for the lock to become free. | ||
206 | */ | ||
207 | int maple_add_packet_sleeps(struct maple_device *mdev, u32 function, | ||
208 | u32 command, size_t length, void *data) | ||
209 | { | ||
210 | int locking, ret = 0; | ||
211 | void *sendbuf = NULL; | ||
212 | |||
213 | locking = mutex_lock_interruptible(&mdev->mq->mutex); | ||
214 | if (locking) { | ||
215 | ret = -EIO; | ||
216 | goto out; | ||
217 | } | ||
218 | |||
219 | if (length) { | ||
220 | sendbuf = kmalloc(length * 4, GFP_KERNEL); | ||
221 | if (!sendbuf) { | ||
222 | mutex_unlock(&mdev->mq->mutex); | ||
223 | ret = -ENOMEM; | 165 | ret = -ENOMEM; |
224 | goto out; | 166 | goto out; |
225 | } | 167 | } |
@@ -233,38 +175,35 @@ int maple_add_packet_sleeps(struct maple_device *mdev, u32 function, | |||
233 | mdev->mq->sendbuf = sendbuf; | 175 | mdev->mq->sendbuf = sendbuf; |
234 | 176 | ||
235 | mutex_lock(&maple_wlist_lock); | 177 | mutex_lock(&maple_wlist_lock); |
236 | list_add(&mdev->mq->list, &maple_waitq); | 178 | list_add_tail(&mdev->mq->list, &maple_waitq); |
237 | mutex_unlock(&maple_wlist_lock); | 179 | mutex_unlock(&maple_wlist_lock); |
238 | out: | 180 | out: |
239 | return ret; | 181 | return ret; |
240 | } | 182 | } |
241 | EXPORT_SYMBOL_GPL(maple_add_packet_sleeps); | 183 | EXPORT_SYMBOL_GPL(maple_add_packet); |
242 | 184 | ||
243 | static struct mapleq *maple_allocq(struct maple_device *mdev) | 185 | static struct mapleq *maple_allocq(struct maple_device *mdev) |
244 | { | 186 | { |
245 | struct mapleq *mq; | 187 | struct mapleq *mq; |
246 | 188 | ||
247 | mq = kmalloc(sizeof(*mq), GFP_KERNEL); | 189 | mq = kzalloc(sizeof(*mq), GFP_KERNEL); |
248 | if (!mq) | 190 | if (!mq) |
249 | goto failed_nomem; | 191 | goto failed_nomem; |
250 | 192 | ||
193 | INIT_LIST_HEAD(&mq->list); | ||
251 | mq->dev = mdev; | 194 | mq->dev = mdev; |
252 | mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); | 195 | mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); |
253 | mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); | ||
254 | if (!mq->recvbuf) | 196 | if (!mq->recvbuf) |
255 | goto failed_p2; | 197 | goto failed_p2; |
256 | /* | 198 | mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]); |
257 | * most devices do not need the mutex - but | ||
258 | * anything that injects block reads or writes | ||
259 | * will rely on it | ||
260 | */ | ||
261 | mutex_init(&mq->mutex); | ||
262 | 199 | ||
263 | return mq; | 200 | return mq; |
264 | 201 | ||
265 | failed_p2: | 202 | failed_p2: |
266 | kfree(mq); | 203 | kfree(mq); |
267 | failed_nomem: | 204 | failed_nomem: |
205 | dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n", | ||
206 | mdev->port, mdev->unit); | ||
268 | return NULL; | 207 | return NULL; |
269 | } | 208 | } |
270 | 209 | ||
@@ -272,12 +211,16 @@ static struct maple_device *maple_alloc_dev(int port, int unit) | |||
272 | { | 211 | { |
273 | struct maple_device *mdev; | 212 | struct maple_device *mdev; |
274 | 213 | ||
214 | /* zero this out to avoid kobj subsystem | ||
215 | * thinking it has already been registered */ | ||
216 | |||
275 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | 217 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); |
276 | if (!mdev) | 218 | if (!mdev) |
277 | return NULL; | 219 | return NULL; |
278 | 220 | ||
279 | mdev->port = port; | 221 | mdev->port = port; |
280 | mdev->unit = unit; | 222 | mdev->unit = unit; |
223 | |||
281 | mdev->mq = maple_allocq(mdev); | 224 | mdev->mq = maple_allocq(mdev); |
282 | 225 | ||
283 | if (!mdev->mq) { | 226 | if (!mdev->mq) { |
@@ -286,19 +229,14 @@ static struct maple_device *maple_alloc_dev(int port, int unit) | |||
286 | } | 229 | } |
287 | mdev->dev.bus = &maple_bus_type; | 230 | mdev->dev.bus = &maple_bus_type; |
288 | mdev->dev.parent = &maple_bus; | 231 | mdev->dev.parent = &maple_bus; |
232 | init_waitqueue_head(&mdev->maple_wait); | ||
289 | return mdev; | 233 | return mdev; |
290 | } | 234 | } |
291 | 235 | ||
292 | static void maple_free_dev(struct maple_device *mdev) | 236 | static void maple_free_dev(struct maple_device *mdev) |
293 | { | 237 | { |
294 | if (!mdev) | 238 | kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf); |
295 | return; | 239 | kfree(mdev->mq); |
296 | if (mdev->mq) { | ||
297 | if (mdev->mq->recvbufdcsp) | ||
298 | kmem_cache_free(maple_queue_cache, | ||
299 | mdev->mq->recvbufdcsp); | ||
300 | kfree(mdev->mq); | ||
301 | } | ||
302 | kfree(mdev); | 240 | kfree(mdev); |
303 | } | 241 | } |
304 | 242 | ||
@@ -320,7 +258,7 @@ static void maple_build_block(struct mapleq *mq) | |||
320 | maple_lastptr = maple_sendptr; | 258 | maple_lastptr = maple_sendptr; |
321 | 259 | ||
322 | *maple_sendptr++ = (port << 16) | len | 0x80000000; | 260 | *maple_sendptr++ = (port << 16) | len | 0x80000000; |
323 | *maple_sendptr++ = PHYSADDR(mq->recvbuf); | 261 | *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf); |
324 | *maple_sendptr++ = | 262 | *maple_sendptr++ = |
325 | mq->command | (to << 8) | (from << 16) | (len << 24); | 263 | mq->command | (to << 8) | (from << 16) | (len << 24); |
326 | while (len-- > 0) | 264 | while (len-- > 0) |
@@ -333,20 +271,28 @@ static void maple_send(void) | |||
333 | int i, maple_packets = 0; | 271 | int i, maple_packets = 0; |
334 | struct mapleq *mq, *nmq; | 272 | struct mapleq *mq, *nmq; |
335 | 273 | ||
336 | if (!list_empty(&maple_sentq)) | 274 | if (!maple_dma_done()) |
337 | return; | 275 | return; |
276 | |||
277 | /* disable DMA */ | ||
278 | ctrl_outl(0, MAPLE_ENABLE); | ||
279 | |||
280 | if (!list_empty(&maple_sentq)) | ||
281 | goto finish; | ||
282 | |||
338 | mutex_lock(&maple_wlist_lock); | 283 | mutex_lock(&maple_wlist_lock); |
339 | if (list_empty(&maple_waitq) || !maple_dma_done()) { | 284 | if (list_empty(&maple_waitq)) { |
340 | mutex_unlock(&maple_wlist_lock); | 285 | mutex_unlock(&maple_wlist_lock); |
341 | return; | 286 | goto finish; |
342 | } | 287 | } |
343 | mutex_unlock(&maple_wlist_lock); | 288 | |
344 | maple_lastptr = maple_sendbuf; | 289 | maple_lastptr = maple_sendbuf; |
345 | maple_sendptr = maple_sendbuf; | 290 | maple_sendptr = maple_sendbuf; |
346 | mutex_lock(&maple_wlist_lock); | 291 | |
347 | list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { | 292 | list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { |
348 | maple_build_block(mq); | 293 | maple_build_block(mq); |
349 | list_move(&mq->list, &maple_sentq); | 294 | list_del_init(&mq->list); |
295 | list_add_tail(&mq->list, &maple_sentq); | ||
350 | if (maple_packets++ > MAPLE_MAXPACKETS) | 296 | if (maple_packets++ > MAPLE_MAXPACKETS) |
351 | break; | 297 | break; |
352 | } | 298 | } |
@@ -356,10 +302,13 @@ static void maple_send(void) | |||
356 | dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, | 302 | dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, |
357 | PAGE_SIZE, DMA_BIDIRECTIONAL); | 303 | PAGE_SIZE, DMA_BIDIRECTIONAL); |
358 | } | 304 | } |
305 | |||
306 | finish: | ||
307 | maple_dma_reset(); | ||
359 | } | 308 | } |
360 | 309 | ||
361 | /* check if there is a driver registered likely to match this device */ | 310 | /* check if there is a driver registered likely to match this device */ |
362 | static int check_matching_maple_driver(struct device_driver *driver, | 311 | static int maple_check_matching_driver(struct device_driver *driver, |
363 | void *devptr) | 312 | void *devptr) |
364 | { | 313 | { |
365 | struct maple_driver *maple_drv; | 314 | struct maple_driver *maple_drv; |
@@ -374,10 +323,7 @@ static int check_matching_maple_driver(struct device_driver *driver, | |||
374 | 323 | ||
375 | static void maple_detach_driver(struct maple_device *mdev) | 324 | static void maple_detach_driver(struct maple_device *mdev) |
376 | { | 325 | { |
377 | if (!mdev) | ||
378 | return; | ||
379 | device_unregister(&mdev->dev); | 326 | device_unregister(&mdev->dev); |
380 | mdev = NULL; | ||
381 | } | 327 | } |
382 | 328 | ||
383 | /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ | 329 | /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ |
@@ -385,9 +331,9 @@ static void maple_attach_driver(struct maple_device *mdev) | |||
385 | { | 331 | { |
386 | char *p, *recvbuf; | 332 | char *p, *recvbuf; |
387 | unsigned long function; | 333 | unsigned long function; |
388 | int matched, retval; | 334 | int matched, error; |
389 | 335 | ||
390 | recvbuf = mdev->mq->recvbuf; | 336 | recvbuf = mdev->mq->recvbuf->buf; |
391 | /* copy the data as individual elements in | 337 | /* copy the data as individual elements in |
392 | * case of memory optimisation */ | 338 | * case of memory optimisation */ |
393 | memcpy(&mdev->devinfo.function, recvbuf + 4, 4); | 339 | memcpy(&mdev->devinfo.function, recvbuf + 4, 4); |
@@ -395,7 +341,6 @@ static void maple_attach_driver(struct maple_device *mdev) | |||
395 | memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); | 341 | memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); |
396 | memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); | 342 | memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); |
397 | memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); | 343 | memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); |
398 | memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60); | ||
399 | memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); | 344 | memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); |
400 | memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); | 345 | memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); |
401 | memcpy(mdev->product_name, mdev->devinfo.product_name, 30); | 346 | memcpy(mdev->product_name, mdev->devinfo.product_name, 30); |
@@ -414,43 +359,41 @@ static void maple_attach_driver(struct maple_device *mdev) | |||
414 | else | 359 | else |
415 | break; | 360 | break; |
416 | 361 | ||
417 | printk(KERN_INFO "Maple device detected: %s\n", | ||
418 | mdev->product_name); | ||
419 | printk(KERN_INFO "Maple device: %s\n", mdev->product_licence); | ||
420 | |||
421 | function = be32_to_cpu(mdev->devinfo.function); | 362 | function = be32_to_cpu(mdev->devinfo.function); |
422 | 363 | ||
364 | dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n", | ||
365 | mdev->product_name, function, mdev->port, mdev->unit); | ||
366 | |||
423 | if (function > 0x200) { | 367 | if (function > 0x200) { |
424 | /* Do this silently - as not a real device */ | 368 | /* Do this silently - as not a real device */ |
425 | function = 0; | 369 | function = 0; |
426 | mdev->driver = &maple_dummy_driver; | 370 | mdev->driver = &maple_unsupported_device; |
427 | sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port); | 371 | sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port); |
372 | |||
428 | } else { | 373 | } else { |
429 | printk(KERN_INFO | ||
430 | "Maple bus at (%d, %d): Function 0x%lX\n", | ||
431 | mdev->port, mdev->unit, function); | ||
432 | 374 | ||
433 | matched = | 375 | matched = |
434 | bus_for_each_drv(&maple_bus_type, NULL, mdev, | 376 | bus_for_each_drv(&maple_bus_type, NULL, mdev, |
435 | check_matching_maple_driver); | 377 | maple_check_matching_driver); |
436 | 378 | ||
437 | if (matched == 0) { | 379 | if (matched == 0) { |
438 | /* Driver does not exist yet */ | 380 | /* Driver does not exist yet */ |
439 | printk(KERN_INFO | 381 | dev_info(&mdev->dev, "no driver found\n"); |
440 | "No maple driver found.\n"); | 382 | mdev->driver = &maple_unsupported_device; |
441 | mdev->driver = &maple_dummy_driver; | ||
442 | } | 383 | } |
443 | sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port, | 384 | sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port, |
444 | mdev->unit, function); | 385 | mdev->unit, function); |
445 | } | 386 | } |
387 | |||
446 | mdev->function = function; | 388 | mdev->function = function; |
447 | mdev->dev.release = &maple_release_device; | 389 | mdev->dev.release = &maple_release_device; |
448 | retval = device_register(&mdev->dev); | 390 | |
449 | if (retval) { | 391 | atomic_set(&mdev->busy, 0); |
450 | printk(KERN_INFO | 392 | error = device_register(&mdev->dev); |
451 | "Maple bus: Attempt to register device" | 393 | if (error) { |
452 | " (%x, %x) failed.\n", | 394 | dev_warn(&mdev->dev, "could not register device at" |
453 | mdev->port, mdev->unit); | 395 | " (%d, %d), with error 0x%X\n", mdev->unit, |
396 | mdev->port, error); | ||
454 | maple_free_dev(mdev); | 397 | maple_free_dev(mdev); |
455 | mdev = NULL; | 398 | mdev = NULL; |
456 | return; | 399 | return; |
@@ -462,7 +405,7 @@ static void maple_attach_driver(struct maple_device *mdev) | |||
462 | * port and unit then return 1 - allows identification | 405 | * port and unit then return 1 - allows identification |
463 | * of which devices need to be attached or detached | 406 | * of which devices need to be attached or detached |
464 | */ | 407 | */ |
465 | static int detach_maple_device(struct device *device, void *portptr) | 408 | static int check_maple_device(struct device *device, void *portptr) |
466 | { | 409 | { |
467 | struct maple_device_specify *ds; | 410 | struct maple_device_specify *ds; |
468 | struct maple_device *mdev; | 411 | struct maple_device *mdev; |
@@ -477,21 +420,25 @@ static int detach_maple_device(struct device *device, void *portptr) | |||
477 | static int setup_maple_commands(struct device *device, void *ignored) | 420 | static int setup_maple_commands(struct device *device, void *ignored) |
478 | { | 421 | { |
479 | int add; | 422 | int add; |
480 | struct maple_device *maple_dev = to_maple_dev(device); | 423 | struct maple_device *mdev = to_maple_dev(device); |
481 | 424 | if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 && | |
482 | if ((maple_dev->interval > 0) | 425 | time_after(jiffies, mdev->when)) { |
483 | && time_after(jiffies, maple_dev->when)) { | 426 | /* bounce if we cannot add */ |
484 | /* bounce if we cannot lock */ | 427 | add = maple_add_packet(mdev, |
485 | add = maple_add_packet(maple_dev, | 428 | be32_to_cpu(mdev->devinfo.function), |
486 | be32_to_cpu(maple_dev->devinfo.function), | ||
487 | MAPLE_COMMAND_GETCOND, 1, NULL); | 429 | MAPLE_COMMAND_GETCOND, 1, NULL); |
488 | if (!add) | 430 | if (!add) |
489 | maple_dev->when = jiffies + maple_dev->interval; | 431 | mdev->when = jiffies + mdev->interval; |
490 | } else { | 432 | } else { |
491 | if (time_after(jiffies, maple_pnp_time)) | 433 | if (time_after(jiffies, maple_pnp_time)) |
492 | /* This will also bounce */ | 434 | /* Ensure we don't have block reads and devinfo |
493 | maple_add_packet(maple_dev, 0, | 435 | * calls interfering with one another - so flag the |
494 | MAPLE_COMMAND_DEVINFO, 0, NULL); | 436 | * device as busy */ |
437 | if (atomic_read(&mdev->busy) == 0) { | ||
438 | atomic_set(&mdev->busy, 1); | ||
439 | maple_add_packet(mdev, 0, | ||
440 | MAPLE_COMMAND_DEVINFO, 0, NULL); | ||
441 | } | ||
495 | } | 442 | } |
496 | return 0; | 443 | return 0; |
497 | } | 444 | } |
@@ -499,29 +446,50 @@ static int setup_maple_commands(struct device *device, void *ignored) | |||
499 | /* VBLANK bottom half - implemented via workqueue */ | 446 | /* VBLANK bottom half - implemented via workqueue */ |
500 | static void maple_vblank_handler(struct work_struct *work) | 447 | static void maple_vblank_handler(struct work_struct *work) |
501 | { | 448 | { |
502 | if (!list_empty(&maple_sentq) || !maple_dma_done()) | 449 | int x, locking; |
450 | struct maple_device *mdev; | ||
451 | |||
452 | if (!maple_dma_done()) | ||
503 | return; | 453 | return; |
504 | 454 | ||
505 | ctrl_outl(0, MAPLE_ENABLE); | 455 | ctrl_outl(0, MAPLE_ENABLE); |
506 | 456 | ||
457 | if (!list_empty(&maple_sentq)) | ||
458 | goto finish; | ||
459 | |||
460 | /* | ||
461 | * Set up essential commands - to fetch data and | ||
462 | * check devices are still present | ||
463 | */ | ||
507 | bus_for_each_dev(&maple_bus_type, NULL, NULL, | 464 | bus_for_each_dev(&maple_bus_type, NULL, NULL, |
508 | setup_maple_commands); | 465 | setup_maple_commands); |
466 | |||
467 | if (time_after(jiffies, maple_pnp_time)) { | ||
468 | /* | ||
469 | * Scan the empty ports - bus is flakey and may have | ||
470 | * mis-reported emptyness | ||
471 | */ | ||
472 | for (x = 0; x < MAPLE_PORTS; x++) { | ||
473 | if (checked[x] && empty[x]) { | ||
474 | mdev = baseunits[x]; | ||
475 | if (!mdev) | ||
476 | break; | ||
477 | atomic_set(&mdev->busy, 1); | ||
478 | locking = maple_add_packet(mdev, 0, | ||
479 | MAPLE_COMMAND_DEVINFO, 0, NULL); | ||
480 | if (!locking) | ||
481 | break; | ||
482 | } | ||
483 | } | ||
509 | 484 | ||
510 | if (time_after(jiffies, maple_pnp_time)) | ||
511 | maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; | 485 | maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; |
512 | |||
513 | mutex_lock(&maple_wlist_lock); | ||
514 | if (!list_empty(&maple_waitq) && list_empty(&maple_sentq)) { | ||
515 | mutex_unlock(&maple_wlist_lock); | ||
516 | maple_send(); | ||
517 | } else { | ||
518 | mutex_unlock(&maple_wlist_lock); | ||
519 | } | 486 | } |
520 | 487 | ||
521 | maplebus_dma_reset(); | 488 | finish: |
489 | maple_send(); | ||
522 | } | 490 | } |
523 | 491 | ||
524 | /* handle devices added via hotplugs - placing them on queue for DEVINFO*/ | 492 | /* handle devices added via hotplugs - placing them on queue for DEVINFO */ |
525 | static void maple_map_subunits(struct maple_device *mdev, int submask) | 493 | static void maple_map_subunits(struct maple_device *mdev, int submask) |
526 | { | 494 | { |
527 | int retval, k, devcheck; | 495 | int retval, k, devcheck; |
@@ -533,7 +501,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask) | |||
533 | ds.unit = k + 1; | 501 | ds.unit = k + 1; |
534 | retval = | 502 | retval = |
535 | bus_for_each_dev(&maple_bus_type, NULL, &ds, | 503 | bus_for_each_dev(&maple_bus_type, NULL, &ds, |
536 | detach_maple_device); | 504 | check_maple_device); |
537 | if (retval) { | 505 | if (retval) { |
538 | submask = submask >> 1; | 506 | submask = submask >> 1; |
539 | continue; | 507 | continue; |
@@ -543,6 +511,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask) | |||
543 | mdev_add = maple_alloc_dev(mdev->port, k + 1); | 511 | mdev_add = maple_alloc_dev(mdev->port, k + 1); |
544 | if (!mdev_add) | 512 | if (!mdev_add) |
545 | return; | 513 | return; |
514 | atomic_set(&mdev_add->busy, 1); | ||
546 | maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO, | 515 | maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO, |
547 | 0, NULL); | 516 | 0, NULL); |
548 | /* mark that we are checking sub devices */ | 517 | /* mark that we are checking sub devices */ |
@@ -564,27 +533,45 @@ static void maple_clean_submap(struct maple_device *mdev) | |||
564 | } | 533 | } |
565 | 534 | ||
566 | /* handle empty port or hotplug removal */ | 535 | /* handle empty port or hotplug removal */ |
567 | static void maple_response_none(struct maple_device *mdev, | 536 | static void maple_response_none(struct maple_device *mdev) |
568 | struct mapleq *mq) | 537 | { |
569 | { | 538 | maple_clean_submap(mdev); |
570 | if (mdev->unit != 0) { | 539 | |
571 | list_del(&mq->list); | 540 | if (likely(mdev->unit != 0)) { |
572 | maple_clean_submap(mdev); | 541 | /* |
573 | printk(KERN_INFO | 542 | * Block devices play up |
574 | "Maple bus device detaching at (%d, %d)\n", | 543 | * and give the impression they have |
575 | mdev->port, mdev->unit); | 544 | * been removed even when still in place or |
545 | * trip the mtd layer when they have | ||
546 | * really gone - this code traps that eventuality | ||
547 | * and ensures we aren't overloaded with useless | ||
548 | * error messages | ||
549 | */ | ||
550 | if (mdev->can_unload) { | ||
551 | if (!mdev->can_unload(mdev)) { | ||
552 | atomic_set(&mdev->busy, 2); | ||
553 | wake_up(&mdev->maple_wait); | ||
554 | return; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | dev_info(&mdev->dev, "detaching device at (%d, %d)\n", | ||
559 | mdev->port, mdev->unit); | ||
576 | maple_detach_driver(mdev); | 560 | maple_detach_driver(mdev); |
577 | return; | 561 | return; |
578 | } | 562 | } else { |
579 | if (!started || !fullscan) { | 563 | if (!started || !fullscan) { |
580 | if (checked[mdev->port] == false) { | 564 | if (checked[mdev->port] == false) { |
581 | checked[mdev->port] = true; | 565 | checked[mdev->port] = true; |
582 | printk(KERN_INFO "No maple devices attached" | 566 | empty[mdev->port] = true; |
583 | " to port %d\n", mdev->port); | 567 | dev_info(&mdev->dev, "no devices" |
568 | " to port %d\n", mdev->port); | ||
569 | } | ||
570 | return; | ||
584 | } | 571 | } |
585 | return; | ||
586 | } | 572 | } |
587 | maple_clean_submap(mdev); | 573 | /* Some hardware devices generate false detach messages on unit 0 */ |
574 | atomic_set(&mdev->busy, 0); | ||
588 | } | 575 | } |
589 | 576 | ||
590 | /* preprocess hotplugs or scans */ | 577 | /* preprocess hotplugs or scans */ |
@@ -599,8 +586,11 @@ static void maple_response_devinfo(struct maple_device *mdev, | |||
599 | } else { | 586 | } else { |
600 | if (mdev->unit != 0) | 587 | if (mdev->unit != 0) |
601 | maple_attach_driver(mdev); | 588 | maple_attach_driver(mdev); |
589 | if (mdev->unit == 0) { | ||
590 | empty[mdev->port] = false; | ||
591 | maple_attach_driver(mdev); | ||
592 | } | ||
602 | } | 593 | } |
603 | return; | ||
604 | } | 594 | } |
605 | if (mdev->unit == 0) { | 595 | if (mdev->unit == 0) { |
606 | submask = recvbuf[2] & 0x1F; | 596 | submask = recvbuf[2] & 0x1F; |
@@ -611,6 +601,17 @@ static void maple_response_devinfo(struct maple_device *mdev, | |||
611 | } | 601 | } |
612 | } | 602 | } |
613 | 603 | ||
604 | static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf) | ||
605 | { | ||
606 | if (mdev->fileerr_handler) { | ||
607 | mdev->fileerr_handler(mdev, recvbuf); | ||
608 | return; | ||
609 | } else | ||
610 | dev_warn(&mdev->dev, "device at (%d, %d) reports" | ||
611 | "file error 0x%X\n", mdev->port, mdev->unit, | ||
612 | ((int *)recvbuf)[1]); | ||
613 | } | ||
614 | |||
614 | static void maple_port_rescan(void) | 615 | static void maple_port_rescan(void) |
615 | { | 616 | { |
616 | int i; | 617 | int i; |
@@ -621,12 +622,6 @@ static void maple_port_rescan(void) | |||
621 | if (checked[i] == false) { | 622 | if (checked[i] == false) { |
622 | fullscan = 0; | 623 | fullscan = 0; |
623 | mdev = baseunits[i]; | 624 | mdev = baseunits[i]; |
624 | /* | ||
625 | * test lock in case scan has failed | ||
626 | * but device is still locked | ||
627 | */ | ||
628 | if (mutex_is_locked(&mdev->mq->mutex)) | ||
629 | mutex_unlock(&mdev->mq->mutex); | ||
630 | maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO, | 625 | maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO, |
631 | 0, NULL); | 626 | 0, NULL); |
632 | } | 627 | } |
@@ -637,7 +632,7 @@ static void maple_port_rescan(void) | |||
637 | static void maple_dma_handler(struct work_struct *work) | 632 | static void maple_dma_handler(struct work_struct *work) |
638 | { | 633 | { |
639 | struct mapleq *mq, *nmq; | 634 | struct mapleq *mq, *nmq; |
640 | struct maple_device *dev; | 635 | struct maple_device *mdev; |
641 | char *recvbuf; | 636 | char *recvbuf; |
642 | enum maple_code code; | 637 | enum maple_code code; |
643 | 638 | ||
@@ -646,43 +641,56 @@ static void maple_dma_handler(struct work_struct *work) | |||
646 | ctrl_outl(0, MAPLE_ENABLE); | 641 | ctrl_outl(0, MAPLE_ENABLE); |
647 | if (!list_empty(&maple_sentq)) { | 642 | if (!list_empty(&maple_sentq)) { |
648 | list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { | 643 | list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { |
649 | recvbuf = mq->recvbuf; | 644 | mdev = mq->dev; |
645 | recvbuf = mq->recvbuf->buf; | ||
646 | dma_cache_sync(&mdev->dev, recvbuf, 0x400, | ||
647 | DMA_FROM_DEVICE); | ||
650 | code = recvbuf[0]; | 648 | code = recvbuf[0]; |
651 | dev = mq->dev; | ||
652 | kfree(mq->sendbuf); | 649 | kfree(mq->sendbuf); |
653 | mutex_unlock(&mq->mutex); | ||
654 | list_del_init(&mq->list); | 650 | list_del_init(&mq->list); |
655 | |||
656 | switch (code) { | 651 | switch (code) { |
657 | case MAPLE_RESPONSE_NONE: | 652 | case MAPLE_RESPONSE_NONE: |
658 | maple_response_none(dev, mq); | 653 | maple_response_none(mdev); |
659 | break; | 654 | break; |
660 | 655 | ||
661 | case MAPLE_RESPONSE_DEVINFO: | 656 | case MAPLE_RESPONSE_DEVINFO: |
662 | maple_response_devinfo(dev, recvbuf); | 657 | maple_response_devinfo(mdev, recvbuf); |
658 | atomic_set(&mdev->busy, 0); | ||
663 | break; | 659 | break; |
664 | 660 | ||
665 | case MAPLE_RESPONSE_DATATRF: | 661 | case MAPLE_RESPONSE_DATATRF: |
666 | if (dev->callback) | 662 | if (mdev->callback) |
667 | dev->callback(mq); | 663 | mdev->callback(mq); |
664 | atomic_set(&mdev->busy, 0); | ||
665 | wake_up(&mdev->maple_wait); | ||
668 | break; | 666 | break; |
669 | 667 | ||
670 | case MAPLE_RESPONSE_FILEERR: | 668 | case MAPLE_RESPONSE_FILEERR: |
669 | maple_response_fileerr(mdev, recvbuf); | ||
670 | atomic_set(&mdev->busy, 0); | ||
671 | wake_up(&mdev->maple_wait); | ||
672 | break; | ||
673 | |||
671 | case MAPLE_RESPONSE_AGAIN: | 674 | case MAPLE_RESPONSE_AGAIN: |
672 | case MAPLE_RESPONSE_BADCMD: | 675 | case MAPLE_RESPONSE_BADCMD: |
673 | case MAPLE_RESPONSE_BADFUNC: | 676 | case MAPLE_RESPONSE_BADFUNC: |
674 | printk(KERN_DEBUG | 677 | dev_warn(&mdev->dev, "non-fatal error" |
675 | "Maple non-fatal error 0x%X\n", | 678 | " 0x%X at (%d, %d)\n", code, |
676 | code); | 679 | mdev->port, mdev->unit); |
680 | atomic_set(&mdev->busy, 0); | ||
677 | break; | 681 | break; |
678 | 682 | ||
679 | case MAPLE_RESPONSE_ALLINFO: | 683 | case MAPLE_RESPONSE_ALLINFO: |
680 | printk(KERN_DEBUG | 684 | dev_notice(&mdev->dev, "extended" |
681 | "Maple - extended device information" | 685 | " device information request for (%d, %d)" |
682 | " not supported\n"); | 686 | " but call is not supported\n", mdev->port, |
687 | mdev->unit); | ||
688 | atomic_set(&mdev->busy, 0); | ||
683 | break; | 689 | break; |
684 | 690 | ||
685 | case MAPLE_RESPONSE_OK: | 691 | case MAPLE_RESPONSE_OK: |
692 | atomic_set(&mdev->busy, 0); | ||
693 | wake_up(&mdev->maple_wait); | ||
686 | break; | 694 | break; |
687 | 695 | ||
688 | default: | 696 | default: |
@@ -699,20 +707,19 @@ static void maple_dma_handler(struct work_struct *work) | |||
699 | if (!fullscan) | 707 | if (!fullscan) |
700 | maple_port_rescan(); | 708 | maple_port_rescan(); |
701 | /* mark that we have been through the first scan */ | 709 | /* mark that we have been through the first scan */ |
702 | if (started == 0) | 710 | started = 1; |
703 | started = 1; | ||
704 | } | 711 | } |
705 | maplebus_dma_reset(); | 712 | maple_send(); |
706 | } | 713 | } |
707 | 714 | ||
708 | static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) | 715 | static irqreturn_t maple_dma_interrupt(int irq, void *dev_id) |
709 | { | 716 | { |
710 | /* Load everything into the bottom half */ | 717 | /* Load everything into the bottom half */ |
711 | schedule_work(&maple_dma_process); | 718 | schedule_work(&maple_dma_process); |
712 | return IRQ_HANDLED; | 719 | return IRQ_HANDLED; |
713 | } | 720 | } |
714 | 721 | ||
715 | static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) | 722 | static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id) |
716 | { | 723 | { |
717 | schedule_work(&maple_vblank_process); | 724 | schedule_work(&maple_vblank_process); |
718 | return IRQ_HANDLED; | 725 | return IRQ_HANDLED; |
@@ -720,14 +727,14 @@ static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) | |||
720 | 727 | ||
721 | static int maple_set_dma_interrupt_handler(void) | 728 | static int maple_set_dma_interrupt_handler(void) |
722 | { | 729 | { |
723 | return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt, | 730 | return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt, |
724 | IRQF_SHARED, "maple bus DMA", &maple_dummy_driver); | 731 | IRQF_SHARED, "maple bus DMA", &maple_unsupported_device); |
725 | } | 732 | } |
726 | 733 | ||
727 | static int maple_set_vblank_interrupt_handler(void) | 734 | static int maple_set_vblank_interrupt_handler(void) |
728 | { | 735 | { |
729 | return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt, | 736 | return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt, |
730 | IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver); | 737 | IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device); |
731 | } | 738 | } |
732 | 739 | ||
733 | static int maple_get_dma_buffer(void) | 740 | static int maple_get_dma_buffer(void) |
@@ -740,7 +747,7 @@ static int maple_get_dma_buffer(void) | |||
740 | return 0; | 747 | return 0; |
741 | } | 748 | } |
742 | 749 | ||
743 | static int match_maple_bus_driver(struct device *devptr, | 750 | static int maple_match_bus_driver(struct device *devptr, |
744 | struct device_driver *drvptr) | 751 | struct device_driver *drvptr) |
745 | { | 752 | { |
746 | struct maple_driver *maple_drv = to_maple_driver(drvptr); | 753 | struct maple_driver *maple_drv = to_maple_driver(drvptr); |
@@ -765,16 +772,18 @@ static void maple_bus_release(struct device *dev) | |||
765 | { | 772 | { |
766 | } | 773 | } |
767 | 774 | ||
768 | static struct maple_driver maple_dummy_driver = { | 775 | static struct maple_driver maple_unsupported_device = { |
769 | .drv = { | 776 | .drv = { |
770 | .name = "maple_dummy_driver", | 777 | .name = "maple_unsupported_device", |
771 | .bus = &maple_bus_type, | 778 | .bus = &maple_bus_type, |
772 | }, | 779 | }, |
773 | }; | 780 | }; |
774 | 781 | /** | |
782 | * maple_bus_type - core maple bus structure | ||
783 | */ | ||
775 | struct bus_type maple_bus_type = { | 784 | struct bus_type maple_bus_type = { |
776 | .name = "maple", | 785 | .name = "maple", |
777 | .match = match_maple_bus_driver, | 786 | .match = maple_match_bus_driver, |
778 | .uevent = maple_bus_uevent, | 787 | .uevent = maple_bus_uevent, |
779 | }; | 788 | }; |
780 | EXPORT_SYMBOL_GPL(maple_bus_type); | 789 | EXPORT_SYMBOL_GPL(maple_bus_type); |
@@ -788,7 +797,8 @@ static int __init maple_bus_init(void) | |||
788 | { | 797 | { |
789 | int retval, i; | 798 | int retval, i; |
790 | struct maple_device *mdev[MAPLE_PORTS]; | 799 | struct maple_device *mdev[MAPLE_PORTS]; |
791 | ctrl_outl(0, MAPLE_STATE); | 800 | |
801 | ctrl_outl(0, MAPLE_ENABLE); | ||
792 | 802 | ||
793 | retval = device_register(&maple_bus); | 803 | retval = device_register(&maple_bus); |
794 | if (retval) | 804 | if (retval) |
@@ -798,36 +808,33 @@ static int __init maple_bus_init(void) | |||
798 | if (retval) | 808 | if (retval) |
799 | goto cleanup_device; | 809 | goto cleanup_device; |
800 | 810 | ||
801 | retval = driver_register(&maple_dummy_driver.drv); | 811 | retval = driver_register(&maple_unsupported_device.drv); |
802 | if (retval) | 812 | if (retval) |
803 | goto cleanup_bus; | 813 | goto cleanup_bus; |
804 | 814 | ||
805 | /* allocate memory for maple bus dma */ | 815 | /* allocate memory for maple bus dma */ |
806 | retval = maple_get_dma_buffer(); | 816 | retval = maple_get_dma_buffer(); |
807 | if (retval) { | 817 | if (retval) { |
808 | printk(KERN_INFO | 818 | dev_err(&maple_bus, "failed to allocate DMA buffers\n"); |
809 | "Maple bus: Failed to allocate Maple DMA buffers\n"); | ||
810 | goto cleanup_basic; | 819 | goto cleanup_basic; |
811 | } | 820 | } |
812 | 821 | ||
813 | /* set up DMA interrupt handler */ | 822 | /* set up DMA interrupt handler */ |
814 | retval = maple_set_dma_interrupt_handler(); | 823 | retval = maple_set_dma_interrupt_handler(); |
815 | if (retval) { | 824 | if (retval) { |
816 | printk(KERN_INFO | 825 | dev_err(&maple_bus, "bus failed to grab maple " |
817 | "Maple bus: Failed to grab maple DMA IRQ\n"); | 826 | "DMA IRQ\n"); |
818 | goto cleanup_dma; | 827 | goto cleanup_dma; |
819 | } | 828 | } |
820 | 829 | ||
821 | /* set up VBLANK interrupt handler */ | 830 | /* set up VBLANK interrupt handler */ |
822 | retval = maple_set_vblank_interrupt_handler(); | 831 | retval = maple_set_vblank_interrupt_handler(); |
823 | if (retval) { | 832 | if (retval) { |
824 | printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); | 833 | dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n"); |
825 | goto cleanup_irq; | 834 | goto cleanup_irq; |
826 | } | 835 | } |
827 | 836 | ||
828 | maple_queue_cache = | 837 | maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN); |
829 | kmem_cache_create("maple_queue_cache", 0x400, 0, | ||
830 | SLAB_HWCACHE_ALIGN, NULL); | ||
831 | 838 | ||
832 | if (!maple_queue_cache) | 839 | if (!maple_queue_cache) |
833 | goto cleanup_bothirqs; | 840 | goto cleanup_bothirqs; |
@@ -838,23 +845,23 @@ static int __init maple_bus_init(void) | |||
838 | /* setup maple ports */ | 845 | /* setup maple ports */ |
839 | for (i = 0; i < MAPLE_PORTS; i++) { | 846 | for (i = 0; i < MAPLE_PORTS; i++) { |
840 | checked[i] = false; | 847 | checked[i] = false; |
848 | empty[i] = false; | ||
841 | mdev[i] = maple_alloc_dev(i, 0); | 849 | mdev[i] = maple_alloc_dev(i, 0); |
842 | baseunits[i] = mdev[i]; | ||
843 | if (!mdev[i]) { | 850 | if (!mdev[i]) { |
844 | while (i-- > 0) | 851 | while (i-- > 0) |
845 | maple_free_dev(mdev[i]); | 852 | maple_free_dev(mdev[i]); |
846 | goto cleanup_cache; | 853 | goto cleanup_cache; |
847 | } | 854 | } |
855 | baseunits[i] = mdev[i]; | ||
856 | atomic_set(&mdev[i]->busy, 1); | ||
848 | maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL); | 857 | maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL); |
849 | subdevice_map[i] = 0; | 858 | subdevice_map[i] = 0; |
850 | } | 859 | } |
851 | 860 | ||
852 | /* setup maplebus hardware */ | 861 | maple_pnp_time = jiffies + HZ; |
853 | maplebus_dma_reset(); | 862 | /* prepare initial queue */ |
854 | /* initial detection */ | ||
855 | maple_send(); | 863 | maple_send(); |
856 | maple_pnp_time = jiffies; | 864 | dev_info(&maple_bus, "bus core now registered\n"); |
857 | printk(KERN_INFO "Maple bus core now registered.\n"); | ||
858 | 865 | ||
859 | return 0; | 866 | return 0; |
860 | 867 | ||
@@ -871,7 +878,7 @@ cleanup_dma: | |||
871 | free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); | 878 | free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); |
872 | 879 | ||
873 | cleanup_basic: | 880 | cleanup_basic: |
874 | driver_unregister(&maple_dummy_driver.drv); | 881 | driver_unregister(&maple_unsupported_device.drv); |
875 | 882 | ||
876 | cleanup_bus: | 883 | cleanup_bus: |
877 | bus_unregister(&maple_bus_type); | 884 | bus_unregister(&maple_bus_type); |
@@ -880,7 +887,7 @@ cleanup_device: | |||
880 | device_unregister(&maple_bus); | 887 | device_unregister(&maple_bus); |
881 | 888 | ||
882 | cleanup: | 889 | cleanup: |
883 | printk(KERN_INFO "Maple bus registration failed\n"); | 890 | printk(KERN_ERR "Maple bus registration failed\n"); |
884 | return retval; | 891 | return retval; |
885 | } | 892 | } |
886 | /* Push init to later to ensure hardware gets detected */ | 893 | /* Push init to later to ensure hardware gets detected */ |
diff --git a/include/linux/maple.h b/include/linux/maple.h index c23d3f51ba40..d9a51b9b3300 100644 --- a/include/linux/maple.h +++ b/include/linux/maple.h | |||
@@ -8,33 +8,49 @@ extern struct bus_type maple_bus_type; | |||
8 | 8 | ||
9 | /* Maple Bus command and response codes */ | 9 | /* Maple Bus command and response codes */ |
10 | enum maple_code { | 10 | enum maple_code { |
11 | MAPLE_RESPONSE_FILEERR = -5, | 11 | MAPLE_RESPONSE_FILEERR = -5, |
12 | MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ | 12 | MAPLE_RESPONSE_AGAIN, /* retransmit */ |
13 | MAPLE_RESPONSE_BADCMD = -3, | 13 | MAPLE_RESPONSE_BADCMD, |
14 | MAPLE_RESPONSE_BADFUNC = -2, | 14 | MAPLE_RESPONSE_BADFUNC, |
15 | MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ | 15 | MAPLE_RESPONSE_NONE, /* unit didn't respond*/ |
16 | MAPLE_COMMAND_DEVINFO = 1, | 16 | MAPLE_COMMAND_DEVINFO = 1, |
17 | MAPLE_COMMAND_ALLINFO = 2, | 17 | MAPLE_COMMAND_ALLINFO, |
18 | MAPLE_COMMAND_RESET = 3, | 18 | MAPLE_COMMAND_RESET, |
19 | MAPLE_COMMAND_KILL = 4, | 19 | MAPLE_COMMAND_KILL, |
20 | MAPLE_RESPONSE_DEVINFO = 5, | 20 | MAPLE_RESPONSE_DEVINFO, |
21 | MAPLE_RESPONSE_ALLINFO = 6, | 21 | MAPLE_RESPONSE_ALLINFO, |
22 | MAPLE_RESPONSE_OK = 7, | 22 | MAPLE_RESPONSE_OK, |
23 | MAPLE_RESPONSE_DATATRF = 8, | 23 | MAPLE_RESPONSE_DATATRF, |
24 | MAPLE_COMMAND_GETCOND = 9, | 24 | MAPLE_COMMAND_GETCOND, |
25 | MAPLE_COMMAND_GETMINFO = 10, | 25 | MAPLE_COMMAND_GETMINFO, |
26 | MAPLE_COMMAND_BREAD = 11, | 26 | MAPLE_COMMAND_BREAD, |
27 | MAPLE_COMMAND_BWRITE = 12, | 27 | MAPLE_COMMAND_BWRITE, |
28 | MAPLE_COMMAND_SETCOND = 14 | 28 | MAPLE_COMMAND_BSYNC, |
29 | MAPLE_COMMAND_SETCOND, | ||
30 | MAPLE_COMMAND_MICCONTROL | ||
31 | }; | ||
32 | |||
33 | enum maple_file_errors { | ||
34 | MAPLE_FILEERR_INVALID_PARTITION = 0x01000000, | ||
35 | MAPLE_FILEERR_PHASE_ERROR = 0x02000000, | ||
36 | MAPLE_FILEERR_INVALID_BLOCK = 0x04000000, | ||
37 | MAPLE_FILEERR_WRITE_ERROR = 0x08000000, | ||
38 | MAPLE_FILEERR_INVALID_WRITE_LENGTH = 0x10000000, | ||
39 | MAPLE_FILEERR_BAD_CRC = 0x20000000 | ||
40 | }; | ||
41 | |||
42 | struct maple_buffer { | ||
43 | char bufx[0x400]; | ||
44 | void *buf; | ||
29 | }; | 45 | }; |
30 | 46 | ||
31 | struct mapleq { | 47 | struct mapleq { |
32 | struct list_head list; | 48 | struct list_head list; |
33 | struct maple_device *dev; | 49 | struct maple_device *dev; |
34 | void *sendbuf, *recvbuf, *recvbufdcsp; | 50 | struct maple_buffer *recvbuf; |
51 | void *sendbuf, *recvbuf_p2; | ||
35 | unsigned char length; | 52 | unsigned char length; |
36 | enum maple_code command; | 53 | enum maple_code command; |
37 | struct mutex mutex; | ||
38 | }; | 54 | }; |
39 | 55 | ||
40 | struct maple_devinfo { | 56 | struct maple_devinfo { |
@@ -52,11 +68,15 @@ struct maple_device { | |||
52 | struct maple_driver *driver; | 68 | struct maple_driver *driver; |
53 | struct mapleq *mq; | 69 | struct mapleq *mq; |
54 | void (*callback) (struct mapleq * mq); | 70 | void (*callback) (struct mapleq * mq); |
71 | void (*fileerr_handler)(struct maple_device *mdev, void *recvbuf); | ||
72 | int (*can_unload)(struct maple_device *mdev); | ||
55 | unsigned long when, interval, function; | 73 | unsigned long when, interval, function; |
56 | struct maple_devinfo devinfo; | 74 | struct maple_devinfo devinfo; |
57 | unsigned char port, unit; | 75 | unsigned char port, unit; |
58 | char product_name[32]; | 76 | char product_name[32]; |
59 | char product_licence[64]; | 77 | char product_licence[64]; |
78 | atomic_t busy; | ||
79 | wait_queue_head_t maple_wait; | ||
60 | struct device dev; | 80 | struct device dev; |
61 | }; | 81 | }; |
62 | 82 | ||
@@ -72,7 +92,7 @@ void maple_getcond_callback(struct maple_device *dev, | |||
72 | int maple_driver_register(struct maple_driver *); | 92 | int maple_driver_register(struct maple_driver *); |
73 | void maple_driver_unregister(struct maple_driver *); | 93 | void maple_driver_unregister(struct maple_driver *); |
74 | 94 | ||
75 | int maple_add_packet_sleeps(struct maple_device *mdev, u32 function, | 95 | int maple_add_packet(struct maple_device *mdev, u32 function, |
76 | u32 command, u32 length, void *data); | 96 | u32 command, u32 length, void *data); |
77 | void maple_clear_dev(struct maple_device *mdev); | 97 | void maple_clear_dev(struct maple_device *mdev); |
78 | 98 | ||