Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2007 by Alan Stern
0004  */
0005 
0006 /* this file is part of ehci-hcd.c */
0007 
0008 
0009 /* Display the ports dedicated to the companion controller */
0010 static ssize_t companion_show(struct device *dev,
0011                   struct device_attribute *attr,
0012                   char *buf)
0013 {
0014     struct ehci_hcd     *ehci;
0015     int         nports, index, n;
0016     int         count = PAGE_SIZE;
0017     char            *ptr = buf;
0018 
0019     ehci = hcd_to_ehci(dev_get_drvdata(dev));
0020     nports = HCS_N_PORTS(ehci->hcs_params);
0021 
0022     for (index = 0; index < nports; ++index) {
0023         if (test_bit(index, &ehci->companion_ports)) {
0024             n = scnprintf(ptr, count, "%d\n", index + 1);
0025             ptr += n;
0026             count -= n;
0027         }
0028     }
0029     return ptr - buf;
0030 }
0031 
0032 /*
0033  * Dedicate or undedicate a port to the companion controller.
0034  * Syntax is "[-]portnum", where a leading '-' sign means
0035  * return control of the port to the EHCI controller.
0036  */
0037 static ssize_t companion_store(struct device *dev,
0038                    struct device_attribute *attr,
0039                    const char *buf, size_t count)
0040 {
0041     struct ehci_hcd     *ehci;
0042     int         portnum, new_owner;
0043 
0044     ehci = hcd_to_ehci(dev_get_drvdata(dev));
0045     new_owner = PORT_OWNER;     /* Owned by companion */
0046     if (sscanf(buf, "%d", &portnum) != 1)
0047         return -EINVAL;
0048     if (portnum < 0) {
0049         portnum = - portnum;
0050         new_owner = 0;      /* Owned by EHCI */
0051     }
0052     if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
0053         return -ENOENT;
0054     portnum--;
0055     if (new_owner)
0056         set_bit(portnum, &ehci->companion_ports);
0057     else
0058         clear_bit(portnum, &ehci->companion_ports);
0059     set_owner(ehci, portnum, new_owner);
0060     return count;
0061 }
0062 static DEVICE_ATTR_RW(companion);
0063 
0064 
0065 /*
0066  * Display / Set uframe_periodic_max
0067  */
0068 static ssize_t uframe_periodic_max_show(struct device *dev,
0069                     struct device_attribute *attr,
0070                     char *buf)
0071 {
0072     struct ehci_hcd     *ehci;
0073     int         n;
0074 
0075     ehci = hcd_to_ehci(dev_get_drvdata(dev));
0076     n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
0077     return n;
0078 }
0079 
0080 
0081 static ssize_t uframe_periodic_max_store(struct device *dev,
0082                     struct device_attribute *attr,
0083                     const char *buf, size_t count)
0084 {
0085     struct ehci_hcd     *ehci;
0086     unsigned        uframe_periodic_max;
0087     unsigned        uframe;
0088     unsigned long       flags;
0089     ssize_t         ret;
0090 
0091     ehci = hcd_to_ehci(dev_get_drvdata(dev));
0092     if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
0093         return -EINVAL;
0094 
0095     if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
0096         ehci_info(ehci, "rejecting invalid request for "
0097                 "uframe_periodic_max=%u\n", uframe_periodic_max);
0098         return -EINVAL;
0099     }
0100 
0101     ret = -EINVAL;
0102 
0103     /*
0104      * lock, so that our checking does not race with possible periodic
0105      * bandwidth allocation through submitting new urbs.
0106      */
0107     spin_lock_irqsave (&ehci->lock, flags);
0108 
0109     /*
0110      * for request to decrease max periodic bandwidth, we have to check
0111      * to see whether the decrease is possible.
0112      */
0113     if (uframe_periodic_max < ehci->uframe_periodic_max) {
0114         u8      allocated_max = 0;
0115 
0116         for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe)
0117             allocated_max = max(allocated_max,
0118                     ehci->bandwidth[uframe]);
0119 
0120         if (allocated_max > uframe_periodic_max) {
0121             ehci_info(ehci,
0122                 "cannot decrease uframe_periodic_max because "
0123                 "periodic bandwidth is already allocated "
0124                 "(%u > %u)\n",
0125                 allocated_max, uframe_periodic_max);
0126             goto out_unlock;
0127         }
0128     }
0129 
0130     /* increasing is always ok */
0131 
0132     ehci_info(ehci, "setting max periodic bandwidth to %u%% "
0133             "(== %u usec/uframe)\n",
0134             100*uframe_periodic_max/125, uframe_periodic_max);
0135 
0136     if (uframe_periodic_max != 100)
0137         ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
0138 
0139     ehci->uframe_periodic_max = uframe_periodic_max;
0140     ret = count;
0141 
0142 out_unlock:
0143     spin_unlock_irqrestore (&ehci->lock, flags);
0144     return ret;
0145 }
0146 static DEVICE_ATTR_RW(uframe_periodic_max);
0147 
0148 
0149 static inline int create_sysfs_files(struct ehci_hcd *ehci)
0150 {
0151     struct device   *controller = ehci_to_hcd(ehci)->self.controller;
0152     int i = 0;
0153 
0154     /* with integrated TT there is no companion! */
0155     if (!ehci_is_TDI(ehci))
0156         i = device_create_file(controller, &dev_attr_companion);
0157     if (i)
0158         goto out;
0159 
0160     i = device_create_file(controller, &dev_attr_uframe_periodic_max);
0161 out:
0162     return i;
0163 }
0164 
0165 static inline void remove_sysfs_files(struct ehci_hcd *ehci)
0166 {
0167     struct device   *controller = ehci_to_hcd(ehci)->self.controller;
0168 
0169     /* with integrated TT there is no companion! */
0170     if (!ehci_is_TDI(ehci))
0171         device_remove_file(controller, &dev_attr_companion);
0172 
0173     device_remove_file(controller, &dev_attr_uframe_periodic_max);
0174 }