root/drivers/usb/chipidea/debug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ci_device_show
  2. ci_port_test_show
  3. ci_port_test_write
  4. ci_port_test_open
  5. ci_qheads_show
  6. ci_requests_show
  7. ci_otg_show
  8. ci_role_show
  9. ci_role_write
  10. ci_role_open
  11. ci_registers_show
  12. dbg_create_files
  13. dbg_remove_files

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/kernel.h>
   3 #include <linux/device.h>
   4 #include <linux/types.h>
   5 #include <linux/spinlock.h>
   6 #include <linux/debugfs.h>
   7 #include <linux/seq_file.h>
   8 #include <linux/uaccess.h>
   9 #include <linux/usb/ch9.h>
  10 #include <linux/usb/gadget.h>
  11 #include <linux/usb/phy.h>
  12 #include <linux/usb/otg.h>
  13 #include <linux/usb/otg-fsm.h>
  14 #include <linux/usb/chipidea.h>
  15 
  16 #include "ci.h"
  17 #include "udc.h"
  18 #include "bits.h"
  19 #include "otg.h"
  20 
  21 /**
  22  * ci_device_show: prints information about device capabilities and status
  23  */
  24 static int ci_device_show(struct seq_file *s, void *data)
  25 {
  26         struct ci_hdrc *ci = s->private;
  27         struct usb_gadget *gadget = &ci->gadget;
  28 
  29         seq_printf(s, "speed             = %d\n", gadget->speed);
  30         seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
  31         seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
  32         seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
  33         seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
  34         seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
  35         seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
  36         seq_printf(s, "name              = %s\n",
  37                    (gadget->name ? gadget->name : ""));
  38 
  39         if (!ci->driver)
  40                 return 0;
  41 
  42         seq_printf(s, "gadget function   = %s\n",
  43                        (ci->driver->function ? ci->driver->function : ""));
  44         seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
  45 
  46         return 0;
  47 }
  48 DEFINE_SHOW_ATTRIBUTE(ci_device);
  49 
  50 /**
  51  * ci_port_test_show: reads port test mode
  52  */
  53 static int ci_port_test_show(struct seq_file *s, void *data)
  54 {
  55         struct ci_hdrc *ci = s->private;
  56         unsigned long flags;
  57         unsigned mode;
  58 
  59         pm_runtime_get_sync(ci->dev);
  60         spin_lock_irqsave(&ci->lock, flags);
  61         mode = hw_port_test_get(ci);
  62         spin_unlock_irqrestore(&ci->lock, flags);
  63         pm_runtime_put_sync(ci->dev);
  64 
  65         seq_printf(s, "mode = %u\n", mode);
  66 
  67         return 0;
  68 }
  69 
  70 /**
  71  * ci_port_test_write: writes port test mode
  72  */
  73 static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
  74                                   size_t count, loff_t *ppos)
  75 {
  76         struct seq_file *s = file->private_data;
  77         struct ci_hdrc *ci = s->private;
  78         unsigned long flags;
  79         unsigned mode;
  80         char buf[32];
  81         int ret;
  82 
  83         count = min_t(size_t, sizeof(buf) - 1, count);
  84         if (copy_from_user(buf, ubuf, count))
  85                 return -EFAULT;
  86 
  87         /* sscanf requires a zero terminated string */
  88         buf[count] = '\0';
  89 
  90         if (sscanf(buf, "%u", &mode) != 1)
  91                 return -EINVAL;
  92 
  93         if (mode > 255)
  94                 return -EBADRQC;
  95 
  96         pm_runtime_get_sync(ci->dev);
  97         spin_lock_irqsave(&ci->lock, flags);
  98         ret = hw_port_test_set(ci, mode);
  99         spin_unlock_irqrestore(&ci->lock, flags);
 100         pm_runtime_put_sync(ci->dev);
 101 
 102         return ret ? ret : count;
 103 }
 104 
 105 static int ci_port_test_open(struct inode *inode, struct file *file)
 106 {
 107         return single_open(file, ci_port_test_show, inode->i_private);
 108 }
 109 
 110 static const struct file_operations ci_port_test_fops = {
 111         .open           = ci_port_test_open,
 112         .write          = ci_port_test_write,
 113         .read           = seq_read,
 114         .llseek         = seq_lseek,
 115         .release        = single_release,
 116 };
 117 
 118 /**
 119  * ci_qheads_show: DMA contents of all queue heads
 120  */
 121 static int ci_qheads_show(struct seq_file *s, void *data)
 122 {
 123         struct ci_hdrc *ci = s->private;
 124         unsigned long flags;
 125         unsigned i, j;
 126 
 127         if (ci->role != CI_ROLE_GADGET) {
 128                 seq_printf(s, "not in gadget mode\n");
 129                 return 0;
 130         }
 131 
 132         spin_lock_irqsave(&ci->lock, flags);
 133         for (i = 0; i < ci->hw_ep_max/2; i++) {
 134                 struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
 135                 struct ci_hw_ep *hweptx =
 136                         &ci->ci_hw_ep[i + ci->hw_ep_max/2];
 137                 seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
 138                            i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
 139                 for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
 140                         seq_printf(s, " %04X:    %08X    %08X\n", j,
 141                                    *((u32 *)hweprx->qh.ptr + j),
 142                                    *((u32 *)hweptx->qh.ptr + j));
 143         }
 144         spin_unlock_irqrestore(&ci->lock, flags);
 145 
 146         return 0;
 147 }
 148 DEFINE_SHOW_ATTRIBUTE(ci_qheads);
 149 
 150 /**
 151  * ci_requests_show: DMA contents of all requests currently queued (all endpts)
 152  */
 153 static int ci_requests_show(struct seq_file *s, void *data)
 154 {
 155         struct ci_hdrc *ci = s->private;
 156         unsigned long flags;
 157         struct ci_hw_req *req = NULL;
 158         struct td_node *node, *tmpnode;
 159         unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
 160 
 161         if (ci->role != CI_ROLE_GADGET) {
 162                 seq_printf(s, "not in gadget mode\n");
 163                 return 0;
 164         }
 165 
 166         spin_lock_irqsave(&ci->lock, flags);
 167         for (i = 0; i < ci->hw_ep_max; i++)
 168                 list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) {
 169                         list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
 170                                 seq_printf(s, "EP=%02i: TD=%08X %s\n",
 171                                            i % (ci->hw_ep_max / 2),
 172                                            (u32)node->dma,
 173                                            ((i < ci->hw_ep_max/2) ?
 174                                            "RX" : "TX"));
 175 
 176                                 for (j = 0; j < qsize; j++)
 177                                         seq_printf(s, " %04X:    %08X\n", j,
 178                                                    *((u32 *)node->ptr + j));
 179                         }
 180                 }
 181         spin_unlock_irqrestore(&ci->lock, flags);
 182 
 183         return 0;
 184 }
 185 DEFINE_SHOW_ATTRIBUTE(ci_requests);
 186 
 187 static int ci_otg_show(struct seq_file *s, void *unused)
 188 {
 189         struct ci_hdrc *ci = s->private;
 190         struct otg_fsm *fsm;
 191 
 192         if (!ci || !ci_otg_is_fsm_mode(ci))
 193                 return 0;
 194 
 195         fsm = &ci->fsm;
 196 
 197         /* ------ State ----- */
 198         seq_printf(s, "OTG state: %s\n\n",
 199                         usb_otg_state_string(ci->otg.state));
 200 
 201         /* ------ State Machine Variables ----- */
 202         seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
 203 
 204         seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req);
 205 
 206         seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det);
 207 
 208         seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld);
 209 
 210         seq_printf(s, "b_conn: %d\n", fsm->b_conn);
 211 
 212         seq_printf(s, "adp_change: %d\n", fsm->adp_change);
 213 
 214         seq_printf(s, "power_up: %d\n", fsm->power_up);
 215 
 216         seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume);
 217 
 218         seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend);
 219 
 220         seq_printf(s, "a_conn: %d\n", fsm->a_conn);
 221 
 222         seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req);
 223 
 224         seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend);
 225 
 226         seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp);
 227 
 228         seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp);
 229 
 230         seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld);
 231 
 232         seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done);
 233 
 234         seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus);
 235 
 236         seq_printf(s, "loc_conn: %d\n", fsm->loc_conn);
 237 
 238         seq_printf(s, "loc_sof: %d\n", fsm->loc_sof);
 239 
 240         seq_printf(s, "adp_prb: %d\n", fsm->adp_prb);
 241 
 242         seq_printf(s, "id: %d\n", fsm->id);
 243 
 244         seq_printf(s, "protocol: %d\n", fsm->protocol);
 245 
 246         return 0;
 247 }
 248 DEFINE_SHOW_ATTRIBUTE(ci_otg);
 249 
 250 static int ci_role_show(struct seq_file *s, void *data)
 251 {
 252         struct ci_hdrc *ci = s->private;
 253 
 254         if (ci->role != CI_ROLE_END)
 255                 seq_printf(s, "%s\n", ci_role(ci)->name);
 256 
 257         return 0;
 258 }
 259 
 260 static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
 261                              size_t count, loff_t *ppos)
 262 {
 263         struct seq_file *s = file->private_data;
 264         struct ci_hdrc *ci = s->private;
 265         enum ci_role role;
 266         char buf[8];
 267         int ret;
 268 
 269         if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 270                 return -EFAULT;
 271 
 272         for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
 273                 if (ci->roles[role] &&
 274                     !strncmp(buf, ci->roles[role]->name,
 275                              strlen(ci->roles[role]->name)))
 276                         break;
 277 
 278         if (role == CI_ROLE_END || role == ci->role)
 279                 return -EINVAL;
 280 
 281         pm_runtime_get_sync(ci->dev);
 282         disable_irq(ci->irq);
 283         ci_role_stop(ci);
 284         ret = ci_role_start(ci, role);
 285         enable_irq(ci->irq);
 286         pm_runtime_put_sync(ci->dev);
 287 
 288         return ret ? ret : count;
 289 }
 290 
 291 static int ci_role_open(struct inode *inode, struct file *file)
 292 {
 293         return single_open(file, ci_role_show, inode->i_private);
 294 }
 295 
 296 static const struct file_operations ci_role_fops = {
 297         .open           = ci_role_open,
 298         .write          = ci_role_write,
 299         .read           = seq_read,
 300         .llseek         = seq_lseek,
 301         .release        = single_release,
 302 };
 303 
 304 static int ci_registers_show(struct seq_file *s, void *unused)
 305 {
 306         struct ci_hdrc *ci = s->private;
 307         u32 tmp_reg;
 308 
 309         if (!ci || ci->in_lpm)
 310                 return -EPERM;
 311 
 312         /* ------ Registers ----- */
 313         tmp_reg = hw_read_intr_enable(ci);
 314         seq_printf(s, "USBINTR reg: %08x\n", tmp_reg);
 315 
 316         tmp_reg = hw_read_intr_status(ci);
 317         seq_printf(s, "USBSTS reg: %08x\n", tmp_reg);
 318 
 319         tmp_reg = hw_read(ci, OP_USBMODE, ~0);
 320         seq_printf(s, "USBMODE reg: %08x\n", tmp_reg);
 321 
 322         tmp_reg = hw_read(ci, OP_USBCMD, ~0);
 323         seq_printf(s, "USBCMD reg: %08x\n", tmp_reg);
 324 
 325         tmp_reg = hw_read(ci, OP_PORTSC, ~0);
 326         seq_printf(s, "PORTSC reg: %08x\n", tmp_reg);
 327 
 328         if (ci->is_otg) {
 329                 tmp_reg = hw_read_otgsc(ci, ~0);
 330                 seq_printf(s, "OTGSC reg: %08x\n", tmp_reg);
 331         }
 332 
 333         return 0;
 334 }
 335 DEFINE_SHOW_ATTRIBUTE(ci_registers);
 336 
 337 /**
 338  * dbg_create_files: initializes the attribute interface
 339  * @ci: device
 340  *
 341  * This function returns an error code
 342  */
 343 void dbg_create_files(struct ci_hdrc *ci)
 344 {
 345         ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
 346 
 347         debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
 348                             &ci_device_fops);
 349         debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, ci,
 350                             &ci_port_test_fops);
 351         debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
 352                             &ci_qheads_fops);
 353         debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
 354                             &ci_requests_fops);
 355 
 356         if (ci_otg_is_fsm_mode(ci)) {
 357                 debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci,
 358                                     &ci_otg_fops);
 359         }
 360 
 361         debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
 362                             &ci_role_fops);
 363         debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
 364                             &ci_registers_fops);
 365 }
 366 
 367 /**
 368  * dbg_remove_files: destroys the attribute interface
 369  * @ci: device
 370  */
 371 void dbg_remove_files(struct ci_hdrc *ci)
 372 {
 373         debugfs_remove_recursive(ci->debugfs);
 374 }

/* [<][>][^][v][top][bottom][index][help] */