blob: c6f50a257565db0691528ea5341a2a3a9d2d74b0 [file] [log] [blame]
Alexander Shishkine443b332012-05-11 17:25:46 +03001#include <linux/delay.h>
2#include <linux/device.h>
3#include <linux/dmapool.h>
4#include <linux/dma-mapping.h>
5#include <linux/init.h>
6#include <linux/platform_device.h>
7#include <linux/module.h>
8#include <linux/interrupt.h>
9#include <linux/io.h>
10#include <linux/irq.h>
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/pm_runtime.h>
14#include <linux/usb/ch9.h>
15#include <linux/usb/gadget.h>
16#include <linux/usb/otg.h>
17#include <linux/usb/chipidea.h>
18
19#include "ci.h"
20#include "udc.h"
21#include "bits.h"
22#include "debug.h"
23
24/* Interrupt statistics */
25#define ISR_MASK 0x1F
26static struct isr_statistics {
27 u32 test;
28 u32 ui;
29 u32 uei;
30 u32 pci;
31 u32 uri;
32 u32 sli;
33 u32 none;
34 struct {
35 u32 cnt;
36 u32 buf[ISR_MASK+1];
37 u32 idx;
38 } hndl;
39} isr_statistics;
40
41void dbg_interrupt(u32 intmask)
42{
43 if (!intmask) {
44 isr_statistics.none++;
45 return;
46 }
47
48 isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
49 isr_statistics.hndl.idx &= ISR_MASK;
50 isr_statistics.hndl.cnt++;
51
52 if (USBi_URI & intmask)
53 isr_statistics.uri++;
54 if (USBi_PCI & intmask)
55 isr_statistics.pci++;
56 if (USBi_UEI & intmask)
57 isr_statistics.uei++;
58 if (USBi_UI & intmask)
59 isr_statistics.ui++;
60 if (USBi_SLI & intmask)
61 isr_statistics.sli++;
62}
63
64/**
65 * hw_register_read: reads all device registers (execute without interruption)
66 * @buf: destination buffer
67 * @size: buffer size
68 *
69 * This function returns number of registers read
70 */
Richard Zhao26c696c2012-07-07 22:56:40 +080071static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
Alexander Shishkine443b332012-05-11 17:25:46 +030072{
73 unsigned i;
74
Richard Zhao26c696c2012-07-07 22:56:40 +080075 if (size > ci->hw_bank.size)
76 size = ci->hw_bank.size;
Alexander Shishkine443b332012-05-11 17:25:46 +030077
78 for (i = 0; i < size; i++)
Richard Zhao26c696c2012-07-07 22:56:40 +080079 buf[i] = hw_read(ci, i * sizeof(u32), ~0);
Alexander Shishkine443b332012-05-11 17:25:46 +030080
81 return size;
82}
83
84/**
85 * hw_register_write: writes to register
86 * @addr: register address
87 * @data: register value
88 *
89 * This function returns an error code
90 */
Richard Zhao26c696c2012-07-07 22:56:40 +080091static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
Alexander Shishkine443b332012-05-11 17:25:46 +030092{
93 /* align */
94 addr /= sizeof(u32);
95
Richard Zhao26c696c2012-07-07 22:56:40 +080096 if (addr >= ci->hw_bank.size)
Alexander Shishkine443b332012-05-11 17:25:46 +030097 return -EINVAL;
98
99 /* align */
100 addr *= sizeof(u32);
101
Richard Zhao26c696c2012-07-07 22:56:40 +0800102 hw_write(ci, addr, ~0, data);
Alexander Shishkine443b332012-05-11 17:25:46 +0300103 return 0;
104}
105
106/**
107 * hw_intr_clear: disables interrupt & clears interrupt status (execute without
108 * interruption)
109 * @n: interrupt bit
110 *
111 * This function returns an error code
112 */
Richard Zhao26c696c2012-07-07 22:56:40 +0800113static int hw_intr_clear(struct ci13xxx *ci, int n)
Alexander Shishkine443b332012-05-11 17:25:46 +0300114{
115 if (n >= REG_BITS)
116 return -EINVAL;
117
Richard Zhao26c696c2012-07-07 22:56:40 +0800118 hw_write(ci, OP_USBINTR, BIT(n), 0);
119 hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
Alexander Shishkine443b332012-05-11 17:25:46 +0300120 return 0;
121}
122
123/**
124 * hw_intr_force: enables interrupt & forces interrupt status (execute without
125 * interruption)
126 * @n: interrupt bit
127 *
128 * This function returns an error code
129 */
Richard Zhao26c696c2012-07-07 22:56:40 +0800130static int hw_intr_force(struct ci13xxx *ci, int n)
Alexander Shishkine443b332012-05-11 17:25:46 +0300131{
132 if (n >= REG_BITS)
133 return -EINVAL;
134
Richard Zhao26c696c2012-07-07 22:56:40 +0800135 hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
136 hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
137 hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
138 hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
Alexander Shishkine443b332012-05-11 17:25:46 +0300139 return 0;
140}
141
142/**
143 * show_device: prints information about device capabilities and status
144 *
145 * Check "device.h" for details
146 */
147static ssize_t show_device(struct device *dev, struct device_attribute *attr,
148 char *buf)
149{
Richard Zhao26c696c2012-07-07 22:56:40 +0800150 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
151 struct usb_gadget *gadget = &ci->gadget;
Alexander Shishkine443b332012-05-11 17:25:46 +0300152 int n = 0;
153
154 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800155 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300156 return 0;
157 }
158
159 n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
160 gadget->speed);
161 n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
162 gadget->max_speed);
163 /* TODO: Scheduled for removal in 3.8. */
164 n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
165 gadget_is_dualspeed(gadget));
166 n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
167 gadget->is_otg);
168 n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
169 gadget->is_a_peripheral);
170 n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
171 gadget->b_hnp_enable);
172 n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
173 gadget->a_hnp_support);
174 n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
175 gadget->a_alt_hnp_support);
176 n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
177 (gadget->name ? gadget->name : ""));
178
179 return n;
180}
181static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
182
183/**
184 * show_driver: prints information about attached gadget (if any)
185 *
186 * Check "device.h" for details
187 */
188static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
189 char *buf)
190{
Richard Zhao26c696c2012-07-07 22:56:40 +0800191 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
192 struct usb_gadget_driver *driver = ci->driver;
Alexander Shishkine443b332012-05-11 17:25:46 +0300193 int n = 0;
194
195 if (attr == NULL || buf == NULL) {
196 dev_err(dev, "[%s] EINVAL\n", __func__);
197 return 0;
198 }
199
200 if (driver == NULL)
201 return scnprintf(buf, PAGE_SIZE,
202 "There is no gadget attached!\n");
203
204 n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
205 (driver->function ? driver->function : ""));
206 n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
207 driver->max_speed);
208
209 return n;
210}
211static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
212
213/* Maximum event message length */
214#define DBG_DATA_MSG 64UL
215
216/* Maximum event messages */
217#define DBG_DATA_MAX 128UL
218
219/* Event buffer descriptor */
220static struct {
221 char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
222 unsigned idx; /* index */
223 unsigned tty; /* print to console? */
224 rwlock_t lck; /* lock */
225} dbg_data = {
226 .idx = 0,
227 .tty = 0,
228 .lck = __RW_LOCK_UNLOCKED(lck)
229};
230
231/**
232 * dbg_dec: decrements debug event index
233 * @idx: buffer index
234 */
235static void dbg_dec(unsigned *idx)
236{
237 *idx = (*idx - 1) & (DBG_DATA_MAX-1);
238}
239
240/**
241 * dbg_inc: increments debug event index
242 * @idx: buffer index
243 */
244static void dbg_inc(unsigned *idx)
245{
246 *idx = (*idx + 1) & (DBG_DATA_MAX-1);
247}
248
249/**
250 * dbg_print: prints the common part of the event
251 * @addr: endpoint address
252 * @name: event name
253 * @status: status
254 * @extra: extra information
255 */
256static void dbg_print(u8 addr, const char *name, int status, const char *extra)
257{
258 struct timeval tval;
259 unsigned int stamp;
260 unsigned long flags;
261
262 write_lock_irqsave(&dbg_data.lck, flags);
263
264 do_gettimeofday(&tval);
265 stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
266 stamp = stamp * 1000000 + tval.tv_usec;
267
268 scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
269 "%04X\t? %02X %-7.7s %4i ?\t%s\n",
270 stamp, addr, name, status, extra);
271
272 dbg_inc(&dbg_data.idx);
273
274 write_unlock_irqrestore(&dbg_data.lck, flags);
275
276 if (dbg_data.tty != 0)
277 pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
278 stamp, addr, name, status, extra);
279}
280
281/**
282 * dbg_done: prints a DONE event
283 * @addr: endpoint address
284 * @td: transfer descriptor
285 * @status: status
286 */
287void dbg_done(u8 addr, const u32 token, int status)
288{
289 char msg[DBG_DATA_MSG];
290
291 scnprintf(msg, sizeof(msg), "%d %02X",
292 (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
293 (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
294 dbg_print(addr, "DONE", status, msg);
295}
296
297/**
298 * dbg_event: prints a generic event
299 * @addr: endpoint address
300 * @name: event name
301 * @status: status
302 */
303void dbg_event(u8 addr, const char *name, int status)
304{
305 if (name != NULL)
306 dbg_print(addr, name, status, "");
307}
308
309/*
310 * dbg_queue: prints a QUEUE event
311 * @addr: endpoint address
312 * @req: USB request
313 * @status: status
314 */
315void dbg_queue(u8 addr, const struct usb_request *req, int status)
316{
317 char msg[DBG_DATA_MSG];
318
319 if (req != NULL) {
320 scnprintf(msg, sizeof(msg),
321 "%d %d", !req->no_interrupt, req->length);
322 dbg_print(addr, "QUEUE", status, msg);
323 }
324}
325
326/**
327 * dbg_setup: prints a SETUP event
328 * @addr: endpoint address
329 * @req: setup request
330 */
331void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
332{
333 char msg[DBG_DATA_MSG];
334
335 if (req != NULL) {
336 scnprintf(msg, sizeof(msg),
337 "%02X %02X %04X %04X %d", req->bRequestType,
338 req->bRequest, le16_to_cpu(req->wValue),
339 le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
340 dbg_print(addr, "SETUP", 0, msg);
341 }
342}
343
344/**
345 * show_events: displays the event buffer
346 *
347 * Check "device.h" for details
348 */
349static ssize_t show_events(struct device *dev, struct device_attribute *attr,
350 char *buf)
351{
352 unsigned long flags;
353 unsigned i, j, n = 0;
354
355 if (attr == NULL || buf == NULL) {
356 dev_err(dev->parent, "[%s] EINVAL\n", __func__);
357 return 0;
358 }
359
360 read_lock_irqsave(&dbg_data.lck, flags);
361
362 i = dbg_data.idx;
363 for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
364 n += strlen(dbg_data.buf[i]);
365 if (n >= PAGE_SIZE) {
366 n -= strlen(dbg_data.buf[i]);
367 break;
368 }
369 }
370 for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
371 j += scnprintf(buf + j, PAGE_SIZE - j,
372 "%s", dbg_data.buf[i]);
373
374 read_unlock_irqrestore(&dbg_data.lck, flags);
375
376 return n;
377}
378
379/**
380 * store_events: configure if events are going to be also printed to console
381 *
382 * Check "device.h" for details
383 */
384static ssize_t store_events(struct device *dev, struct device_attribute *attr,
385 const char *buf, size_t count)
386{
387 unsigned tty;
388
389 if (attr == NULL || buf == NULL) {
390 dev_err(dev, "[%s] EINVAL\n", __func__);
391 goto done;
392 }
393
394 if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
395 dev_err(dev, "<1|0>: enable|disable console log\n");
396 goto done;
397 }
398
399 dbg_data.tty = tty;
400 dev_info(dev, "tty = %u", dbg_data.tty);
401
402 done:
403 return count;
404}
405static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
406
407/**
408 * show_inters: interrupt status, enable status and historic
409 *
410 * Check "device.h" for details
411 */
412static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
413 char *buf)
414{
Richard Zhao26c696c2012-07-07 22:56:40 +0800415 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300416 unsigned long flags;
417 u32 intr;
418 unsigned i, j, n = 0;
419
420 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800421 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300422 return 0;
423 }
424
Richard Zhao26c696c2012-07-07 22:56:40 +0800425 spin_lock_irqsave(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300426
427 /*n += scnprintf(buf + n, PAGE_SIZE - n,
Richard Zhao26c696c2012-07-07 22:56:40 +0800428 "status = %08x\n", hw_read_intr_status(ci));
Alexander Shishkine443b332012-05-11 17:25:46 +0300429 n += scnprintf(buf + n, PAGE_SIZE - n,
Richard Zhao26c696c2012-07-07 22:56:40 +0800430 "enable = %08x\n", hw_read_intr_enable(ci));*/
Alexander Shishkine443b332012-05-11 17:25:46 +0300431
432 n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
433 isr_statistics.test);
434 n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
435 isr_statistics.ui);
436 n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
437 isr_statistics.uei);
438 n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
439 isr_statistics.pci);
440 n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
441 isr_statistics.uri);
442 n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
443 isr_statistics.sli);
444 n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
445 isr_statistics.none);
446 n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
447 isr_statistics.hndl.cnt);
448
449 for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
450 i &= ISR_MASK;
451 intr = isr_statistics.hndl.buf[i];
452
453 if (USBi_UI & intr)
454 n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
455 intr &= ~USBi_UI;
456 if (USBi_UEI & intr)
457 n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
458 intr &= ~USBi_UEI;
459 if (USBi_PCI & intr)
460 n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
461 intr &= ~USBi_PCI;
462 if (USBi_URI & intr)
463 n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
464 intr &= ~USBi_URI;
465 if (USBi_SLI & intr)
466 n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
467 intr &= ~USBi_SLI;
468 if (intr)
469 n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
470 if (isr_statistics.hndl.buf[i])
471 n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
472 }
473
Richard Zhao26c696c2012-07-07 22:56:40 +0800474 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300475
476 return n;
477}
478
479/**
480 * store_inters: enable & force or disable an individual interrutps
481 * (to be used for test purposes only)
482 *
483 * Check "device.h" for details
484 */
485static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
486 const char *buf, size_t count)
487{
Richard Zhao26c696c2012-07-07 22:56:40 +0800488 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300489 unsigned long flags;
490 unsigned en, bit;
491
492 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800493 dev_err(ci->dev, "EINVAL\n");
Alexander Shishkine443b332012-05-11 17:25:46 +0300494 goto done;
495 }
496
497 if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800498 dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
Alexander Shishkine443b332012-05-11 17:25:46 +0300499 goto done;
500 }
501
Richard Zhao26c696c2012-07-07 22:56:40 +0800502 spin_lock_irqsave(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300503 if (en) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800504 if (hw_intr_force(ci, bit))
Alexander Shishkine443b332012-05-11 17:25:46 +0300505 dev_err(dev, "invalid bit number\n");
506 else
507 isr_statistics.test++;
508 } else {
Richard Zhao26c696c2012-07-07 22:56:40 +0800509 if (hw_intr_clear(ci, bit))
Alexander Shishkine443b332012-05-11 17:25:46 +0300510 dev_err(dev, "invalid bit number\n");
511 }
Richard Zhao26c696c2012-07-07 22:56:40 +0800512 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300513
514 done:
515 return count;
516}
517static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
518
519/**
520 * show_port_test: reads port test mode
521 *
522 * Check "device.h" for details
523 */
524static ssize_t show_port_test(struct device *dev,
525 struct device_attribute *attr, char *buf)
526{
Richard Zhao26c696c2012-07-07 22:56:40 +0800527 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300528 unsigned long flags;
529 unsigned mode;
530
531 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800532 dev_err(ci->dev, "EINVAL\n");
Alexander Shishkine443b332012-05-11 17:25:46 +0300533 return 0;
534 }
535
Richard Zhao26c696c2012-07-07 22:56:40 +0800536 spin_lock_irqsave(&ci->lock, flags);
537 mode = hw_port_test_get(ci);
538 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300539
540 return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
541}
542
543/**
544 * store_port_test: writes port test mode
545 *
546 * Check "device.h" for details
547 */
548static ssize_t store_port_test(struct device *dev,
549 struct device_attribute *attr,
550 const char *buf, size_t count)
551{
Richard Zhao26c696c2012-07-07 22:56:40 +0800552 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300553 unsigned long flags;
554 unsigned mode;
555
556 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800557 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300558 goto done;
559 }
560
561 if (sscanf(buf, "%u", &mode) != 1) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800562 dev_err(ci->dev, "<mode>: set port test mode");
Alexander Shishkine443b332012-05-11 17:25:46 +0300563 goto done;
564 }
565
Richard Zhao26c696c2012-07-07 22:56:40 +0800566 spin_lock_irqsave(&ci->lock, flags);
567 if (hw_port_test_set(ci, mode))
568 dev_err(ci->dev, "invalid mode\n");
569 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300570
571 done:
572 return count;
573}
574static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
575 show_port_test, store_port_test);
576
577/**
578 * show_qheads: DMA contents of all queue heads
579 *
580 * Check "device.h" for details
581 */
582static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
583 char *buf)
584{
Richard Zhao26c696c2012-07-07 22:56:40 +0800585 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300586 unsigned long flags;
587 unsigned i, j, n = 0;
588
589 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800590 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300591 return 0;
592 }
593
Richard Zhao26c696c2012-07-07 22:56:40 +0800594 spin_lock_irqsave(&ci->lock, flags);
595 for (i = 0; i < ci->hw_ep_max/2; i++) {
596 struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
Alexander Shishkine443b332012-05-11 17:25:46 +0300597 struct ci13xxx_ep *mEpTx =
Richard Zhao26c696c2012-07-07 22:56:40 +0800598 &ci->ci13xxx_ep[i + ci->hw_ep_max/2];
Alexander Shishkine443b332012-05-11 17:25:46 +0300599 n += scnprintf(buf + n, PAGE_SIZE - n,
600 "EP=%02i: RX=%08X TX=%08X\n",
601 i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
602 for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
603 n += scnprintf(buf + n, PAGE_SIZE - n,
604 " %04X: %08X %08X\n", j,
605 *((u32 *)mEpRx->qh.ptr + j),
606 *((u32 *)mEpTx->qh.ptr + j));
607 }
608 }
Richard Zhao26c696c2012-07-07 22:56:40 +0800609 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300610
611 return n;
612}
613static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
614
615/**
616 * show_registers: dumps all registers
617 *
618 * Check "device.h" for details
619 */
620#define DUMP_ENTRIES 512
621static ssize_t show_registers(struct device *dev,
622 struct device_attribute *attr, char *buf)
623{
Richard Zhao26c696c2012-07-07 22:56:40 +0800624 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300625 unsigned long flags;
626 u32 *dump;
627 unsigned i, k, n = 0;
628
629 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800630 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300631 return 0;
632 }
633
634 dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
635 if (!dump) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800636 dev_err(ci->dev, "%s: out of memory\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300637 return 0;
638 }
639
Richard Zhao26c696c2012-07-07 22:56:40 +0800640 spin_lock_irqsave(&ci->lock, flags);
641 k = hw_register_read(ci, dump, DUMP_ENTRIES);
642 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300643
644 for (i = 0; i < k; i++) {
645 n += scnprintf(buf + n, PAGE_SIZE - n,
646 "reg[0x%04X] = 0x%08X\n",
647 i * (unsigned)sizeof(u32), dump[i]);
648 }
649 kfree(dump);
650
651 return n;
652}
653
654/**
655 * store_registers: writes value to register address
656 *
657 * Check "device.h" for details
658 */
659static ssize_t store_registers(struct device *dev,
660 struct device_attribute *attr,
661 const char *buf, size_t count)
662{
Richard Zhao26c696c2012-07-07 22:56:40 +0800663 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300664 unsigned long addr, data, flags;
665
666 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800667 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300668 goto done;
669 }
670
671 if (sscanf(buf, "%li %li", &addr, &data) != 2) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800672 dev_err(ci->dev,
Alexander Shishkine443b332012-05-11 17:25:46 +0300673 "<addr> <data>: write data to register address\n");
674 goto done;
675 }
676
Richard Zhao26c696c2012-07-07 22:56:40 +0800677 spin_lock_irqsave(&ci->lock, flags);
678 if (hw_register_write(ci, addr, data))
679 dev_err(ci->dev, "invalid address range\n");
680 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300681
682 done:
683 return count;
684}
685static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
686 show_registers, store_registers);
687
688/**
689 * show_requests: DMA contents of all requests currently queued (all endpts)
690 *
691 * Check "device.h" for details
692 */
693static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
694 char *buf)
695{
Richard Zhao26c696c2012-07-07 22:56:40 +0800696 struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
Alexander Shishkine443b332012-05-11 17:25:46 +0300697 unsigned long flags;
698 struct list_head *ptr = NULL;
699 struct ci13xxx_req *req = NULL;
700 unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
701
702 if (attr == NULL || buf == NULL) {
Richard Zhao26c696c2012-07-07 22:56:40 +0800703 dev_err(ci->dev, "[%s] EINVAL\n", __func__);
Alexander Shishkine443b332012-05-11 17:25:46 +0300704 return 0;
705 }
706
Richard Zhao26c696c2012-07-07 22:56:40 +0800707 spin_lock_irqsave(&ci->lock, flags);
708 for (i = 0; i < ci->hw_ep_max; i++)
709 list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
Alexander Shishkine443b332012-05-11 17:25:46 +0300710 {
711 req = list_entry(ptr, struct ci13xxx_req, queue);
712
713 n += scnprintf(buf + n, PAGE_SIZE - n,
714 "EP=%02i: TD=%08X %s\n",
Richard Zhao26c696c2012-07-07 22:56:40 +0800715 i % ci->hw_ep_max/2, (u32)req->dma,
716 ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
Alexander Shishkine443b332012-05-11 17:25:46 +0300717
718 for (j = 0; j < qSize; j++)
719 n += scnprintf(buf + n, PAGE_SIZE - n,
720 " %04X: %08X\n", j,
721 *((u32 *)req->ptr + j));
722 }
Richard Zhao26c696c2012-07-07 22:56:40 +0800723 spin_unlock_irqrestore(&ci->lock, flags);
Alexander Shishkine443b332012-05-11 17:25:46 +0300724
725 return n;
726}
727static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
728
729/**
730 * dbg_create_files: initializes the attribute interface
731 * @dev: device
732 *
733 * This function returns an error code
734 */
735int dbg_create_files(struct device *dev)
736{
737 int retval = 0;
738
739 if (dev == NULL)
740 return -EINVAL;
741 retval = device_create_file(dev, &dev_attr_device);
742 if (retval)
743 goto done;
744 retval = device_create_file(dev, &dev_attr_driver);
745 if (retval)
746 goto rm_device;
747 retval = device_create_file(dev, &dev_attr_events);
748 if (retval)
749 goto rm_driver;
750 retval = device_create_file(dev, &dev_attr_inters);
751 if (retval)
752 goto rm_events;
753 retval = device_create_file(dev, &dev_attr_port_test);
754 if (retval)
755 goto rm_inters;
756 retval = device_create_file(dev, &dev_attr_qheads);
757 if (retval)
758 goto rm_port_test;
759 retval = device_create_file(dev, &dev_attr_registers);
760 if (retval)
761 goto rm_qheads;
762 retval = device_create_file(dev, &dev_attr_requests);
763 if (retval)
764 goto rm_registers;
765 return 0;
766
767 rm_registers:
768 device_remove_file(dev, &dev_attr_registers);
769 rm_qheads:
770 device_remove_file(dev, &dev_attr_qheads);
771 rm_port_test:
772 device_remove_file(dev, &dev_attr_port_test);
773 rm_inters:
774 device_remove_file(dev, &dev_attr_inters);
775 rm_events:
776 device_remove_file(dev, &dev_attr_events);
777 rm_driver:
778 device_remove_file(dev, &dev_attr_driver);
779 rm_device:
780 device_remove_file(dev, &dev_attr_device);
781 done:
782 return retval;
783}
784
785/**
786 * dbg_remove_files: destroys the attribute interface
787 * @dev: device
788 *
789 * This function returns an error code
790 */
791int dbg_remove_files(struct device *dev)
792{
793 if (dev == NULL)
794 return -EINVAL;
795 device_remove_file(dev, &dev_attr_requests);
796 device_remove_file(dev, &dev_attr_registers);
797 device_remove_file(dev, &dev_attr_qheads);
798 device_remove_file(dev, &dev_attr_port_test);
799 device_remove_file(dev, &dev_attr_inters);
800 device_remove_file(dev, &dev_attr_events);
801 device_remove_file(dev, &dev_attr_driver);
802 device_remove_file(dev, &dev_attr_device);
803 return 0;
804}