From 0bcdd9489f3c853cdb38291f1d5385f6ab660223 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 7 Mar 2005 06:52:55 -0800 Subject: [PATCH] USB: add usbmon, a USB monitoring framework This patch adds so-called "usbmon", or USB monitoring framework, similar to what tcpdump provides for Ethernet. This is an initial version, but it should be safe and useful. It adds an overhead of an if () statement into submission and giveback paths even when not monitoring, but this was deemed a lesser evil than stealth manipulation of function pointers. The patch makes two changes to hcd.c which make usbmon more useful: - Change the way we determine that DMA should not be mapped for root hubs, so that usbmon knows easily when it's safe to capture data. - Return exports of usb_bus_list and usb_bus_list_lock for those who wish to build usbmon as a module. This version of the patch changes #define to inlines for hooks and drops extra mod_ops. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/usb.h b/include/linux/usb.h index 7dbcc054c7dc..d4403982dafd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -285,6 +285,10 @@ struct usb_bus { struct class_device class_dev; /* class device for this bus */ void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */ +#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) + struct mon_bus *mon_bus; /* non-null when associated */ + int monitored; /* non-zero when monitored */ +#endif }; #define to_usb_bus(d) container_of(d, struct usb_bus, class_dev) -- cgit v1.2.3 From 9ab81c3936b5e6ff6fd2cf40eccc8d74463f46fc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 7 Mar 2005 06:55:19 -0800 Subject: [PATCH] USB: add This adds a new header file, with definitions for the CDC class constants and structures used by various drivers. For now this only has the ones Linux actually uses. Each one is used in at least two or three different drivers, so sharing the definitions helps reduce errors. It's also a good excuse to make sure there "sparse -Wbitwise" doesn't report errors in how these are used! Patches to those drivers will follow as I have time to verify the updates: - CDC ACM (for serial lines and modems) * Host side support in "cdc-acm" * Peripheral side support in "g_serial" - CDC Ethernet (cable modems, PDAs, etc) * Host side support in "usbnet" * Peripheral side support in "g_ether" Also, Microsoft's RNDIS is a variant of CDC ACM, providing an Ethernet model and implemented by g_ether; it uses these definitions too. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- include/linux/usb_cdc.h | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 include/linux/usb_cdc.h (limited to 'include') diff --git a/include/linux/usb_cdc.h b/include/linux/usb_cdc.h new file mode 100644 index 000000000000..0b8d9a78a51a --- /dev/null +++ b/include/linux/usb_cdc.h @@ -0,0 +1,162 @@ +/* + * USB Communications Device Class (CDC) definitions + * + * CDC says how to talk to lots of different types of network adapters, + * notably ethernet adapters and various modems. It's used mostly with + * firmware based USB peripherals. + */ + +#define USB_CDC_SUBCLASS_ACM 2 +#define USB_CDC_SUBCLASS_ETHERNET 6 + +#define USB_CDC_PROTO_NONE 0 + +#define USB_CDC_ACM_PROTO_AT_V25TER 1 +#define USB_CDC_ACM_PROTO_AT_PCCA101 2 +#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3 +#define USB_CDC_ACM_PROTO_AT_GSM 4 +#define USB_CDC_ACM_PROTO_AT_3G 5 +#define USB_CDC_ACM_PROTO_AT_CDMA 6 +#define USB_CDC_ACM_PROTO_VENDOR 0xff + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific descriptors ... there are a couple dozen of them + */ + +#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ +#define USB_CDC_COUNTRY_TYPE 0x07 +#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ + +/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ +struct usb_cdc_header_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __le16 bcdCDC; +} __attribute__ ((packed)); + +/* "Call Management Descriptor" from CDC spec 5.2.3.2 */ +struct usb_cdc_call_mgmt_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bmCapabilities; +#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01 +#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02 + + __u8 bDataInterface; +} __attribute__ ((packed)); + +/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */ +struct usb_cdc_acm_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bmCapabilities; +} __attribute__ ((packed)); + +/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ +struct usb_cdc_union_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bMasterInterface0; + __u8 bSlaveInterface0; + /* ... and there could be other slave interfaces */ +} __attribute__ ((packed)); + +/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ +struct usb_cdc_ether_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 iMACAddress; + __le32 bmEthernetStatistics; + __le16 wMaxSegmentSize; + __le16 wNumberMCFilters; + __u8 bNumberPowerFilters; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific Control Requests (6.2) + * + * section 3.6.2.1 table 4 has the ACM profile, for modems. + * section 3.8.2 table 10 has the ethernet profile. + * + * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant, + * heavily dependent on the encapsulated (proprietary) command mechanism. + */ + +#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_CDC_REQ_SET_LINE_CODING 0x20 +#define USB_CDC_REQ_GET_LINE_CODING 0x21 +#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 +#define USB_CDC_REQ_SEND_BREAK 0x23 +#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 +#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 +#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 + +/* Line Coding Structure from CDC spec 6.2.13 */ +struct usb_cdc_line_coding { + __le32 dwDTERate; + __u8 bCharFormat; +#define USB_CDC_1_STOP_BITS 0 +#define USB_CDC_1_5_STOP_BITS 1 +#define USB_CDC_2_STOP_BITS 2 + + __u8 bParityType; +#define USB_CDC_NO_PARITY 0 +#define USB_CDC_ODD_PARITY 1 +#define USB_CDC_EVEN_PARITY 2 +#define USB_CDC_MARK_PARITY 3 +#define USB_CDC_SPACE_PARITY 4 + + __u8 bDataBits; +} __attribute__ ((packed)); + +/* table 62; bits in multicast filter */ +#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) +#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ +#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2) +#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3) +#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ + + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific Notifications (6.3) sent by interrupt transfers + * + * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications + * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS + * RNDIS also defines its own bit-incompatible notifications + */ + +#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00 +#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 +#define USB_CDC_NOTIFY_SERIAL_STATE 0x20 +#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a + +struct usb_cdc_notification { + __u8 bmRequestType; + __u8 bNotificationType; + __le16 wValue; + __le16 wIndex; + __le16 wLength; +} __attribute__ ((packed)); + -- cgit v1.2.3 From 56e7cec4797e80a91ab754991a063f5d0282808d Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Mon, 7 Mar 2005 07:19:01 -0800 Subject: [PATCH] include/usb: change USB_CTRL_{SET,GET}_TIMEOUT to msecs Change the units of the timeout constants in usb.h to correspond to the new parameter units for usb_{control,bulk}_msg(), in this case from seconds to milliseconds. Signed-off-by: Nishanth Aravamudan Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/usb.h b/include/linux/usb.h index d4403982dafd..837fadde8d3b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -990,13 +990,13 @@ extern int usb_reset_configuration(struct usb_device *dev); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); /* - * timeouts, in seconds, used for sending/receiving control messages + * timeouts, in milliseconds, used for sending/receiving control messages * they typically complete within a few frames (msec) after they're issued * USB identifies 5 second timeouts, maybe more in a few cases, and a few * slow devices (like some MGE Ellipse UPSes) actually push that limit. */ -#define USB_CTRL_GET_TIMEOUT 5 -#define USB_CTRL_SET_TIMEOUT 5 +#define USB_CTRL_GET_TIMEOUT 5000 +#define USB_CTRL_SET_TIMEOUT 5000 /** -- cgit v1.2.3 From 1d20dd36774235b0b3c39853f26fc46d776bd2ae Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 7 Mar 2005 08:35:50 -0800 Subject: [PATCH] USB: ehci updates for TDI/ATG silicon This patch updates support for the TDI EHCI controller, which is mostly used on non-PCI systems: - Correctly initialize the latest chip, which has both host (EHCI) and peripheral modes. - Initialize split isochronous transfers to use the integrated TT. Most of the patch, by volume, just changes the company name from ARC to TDI in the source code; TransDimension bought ARC's peripheral connectivity business. From: Craig Nadler Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/ehci-hcd.c | 53 +++++++++++++++++++++++++++++++------------ drivers/usb/host/ehci-hub.c | 4 ++-- drivers/usb/host/ehci-q.c | 6 ++--- drivers/usb/host/ehci-sched.c | 8 +++++-- drivers/usb/host/ehci.h | 8 +++---- include/linux/pci_ids.h | 4 ++-- 7 files changed, 56 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 55f5cb9004f8..56fefe16b3ee 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -70,7 +70,7 @@ config USB_EHCI_ROOT_HUB_TT controller is needed. It's safe to say "y" even if your controller doesn't support this feature. - This supports the EHCI implementation from ARC International. + This supports the EHCI implementation from TransDimension Inc. config USB_OHCI_HCD tristate "OHCI HCD support" diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 681b7e25b8eb..b0443f3f6cb1 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -191,9 +191,22 @@ static int ehci_halt (struct ehci_hcd *ehci) return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); } +/* put TDI/ARC silicon into EHCI mode */ +static void tdi_reset (struct ehci_hcd *ehci) +{ + u32 __iomem *reg_ptr; + u32 tmp; + + reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); + tmp = readl (reg_ptr); + tmp |= 0x3; + writel (tmp, reg_ptr); +} + /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset (struct ehci_hcd *ehci) { + int retval; u32 command = readl (&ehci->regs->command); command |= CMD_RESET; @@ -201,7 +214,15 @@ static int ehci_reset (struct ehci_hcd *ehci) writel (command, &ehci->regs->command); ehci_to_hcd(ehci)->state = USB_STATE_HALT; ehci->next_statechange = jiffies; - return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); + retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); + + if (retval) + return retval; + + if (ehci_is_TDI(ehci)) + tdi_reset (ehci); + + return retval; } /* idle the controller (from running) */ @@ -346,11 +367,20 @@ static int ehci_hc_reset (struct usb_hcd *hcd) if (hcd->self.controller->bus == &pci_bus_type) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - /* AMD8111 EHCI doesn't work, according to AMD errata */ - if ((pdev->vendor == PCI_VENDOR_ID_AMD) - && (pdev->device == 0x7463)) { - ehci_info (ehci, "ignoring AMD8111 (errata)\n"); - return -EIO; + switch (pdev->vendor) { + case PCI_VENDOR_ID_TDI: + if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { + ehci->is_tdi_rh_tt = 1; + tdi_reset (ehci); + } + break; + case PCI_VENDOR_ID_AMD: + /* AMD8111 EHCI doesn't work, according to AMD errata */ + if (pdev->device == 0x7463) { + ehci_info (ehci, "ignoring AMD8111 (errata)\n"); + return -EIO; + } + break; } temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); @@ -380,6 +410,8 @@ static int ehci_hc_reset (struct usb_hcd *hcd) ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); return -EIO; } + if (ehci_is_TDI(ehci)) + ehci_reset (ehci); #endif /* cache this readonly data; minimize PCI reads */ @@ -481,15 +513,6 @@ static int ehci_start (struct usb_hcd *hcd) /* help hc dma work well with cachelines */ pci_set_mwi (pdev); - - /* chip-specific init */ - switch (pdev->vendor) { - case PCI_VENDOR_ID_ARC: - if (pdev->device == PCI_DEVICE_ID_ARC_EHCI) - ehci->is_arc_rh_tt = 1; - break; - } - } #endif diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 8a1c130f9448..5d2271314994 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -178,7 +178,7 @@ static int check_reset_complete ( if (!(port_status & PORT_PE)) { /* with integrated TT, there's nobody to hand it to! */ - if (ehci_is_ARC(ehci)) { + if (ehci_is_TDI(ehci)) { ehci_dbg (ehci, "Failed to enable port %d on root hub TT\n", index+1); @@ -517,7 +517,7 @@ static int ehci_hub_control ( * transaction translator built in. */ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT - && !ehci_is_ARC(ehci) + && !ehci_is_TDI(ehci) && PORT_USB11 (temp)) { ehci_dbg (ehci, "port %d low speed --> companion\n", diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b284c4c896af..e9300dbcd229 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -198,7 +198,7 @@ static void qtd_copy_status ( && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) - && (!ehci_is_ARC(ehci) + && (!ehci_is_TDI(ehci) || urb->dev->tt->hub != ehci_to_hcd(ehci)->self.root_hub)) { #ifdef DEBUG @@ -714,10 +714,10 @@ qh_make ( info2 |= (EHCI_TUNE_MULT_TT << 30); info2 |= urb->dev->ttport << 23; - /* set the address of the TT; for ARC's integrated + /* set the address of the TT; for TDI's integrated * root hub tt, leave it zeroed. */ - if (!ehci_is_ARC(ehci) + if (!ehci_is_TDI(ehci) || urb->dev->tt->hub != ehci_to_hcd(ehci)->self.root_hub) info2 |= urb->dev->tt->hub->devnum << 16; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 3cdfb95c3800..9cbde9568218 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -650,6 +650,7 @@ iso_stream_alloc (int mem_flags) static void iso_stream_init ( + struct ehci_hcd *ehci, struct ehci_iso_stream *stream, struct usb_device *dev, int pipe, @@ -701,7 +702,10 @@ iso_stream_init ( u32 addr; addr = dev->ttport << 24; - addr |= dev->tt->hub->devnum << 16; + if (!ehci_is_TDI(ehci) + || (dev->tt->hub != + ehci_to_hcd(ehci)->self.root_hub)) + addr |= dev->tt->hub->devnum << 16; addr |= epnum << 8; addr |= dev->devnum; stream->usecs = HS_USECS_ISO (maxp); @@ -819,7 +823,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* dev->ep owns the initial refcount */ ep->hcpriv = stream; stream->ep = ep; - iso_stream_init(stream, urb->dev, urb->pipe, + iso_stream_init(ehci, stream, urb->dev, urb->pipe, urb->interval); } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index e28d19724f56..671fe3810a1a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -82,7 +82,7 @@ struct ehci_hcd { /* one per controller */ unsigned long next_statechange; u32 command; - unsigned is_arc_rh_tt:1; /* ARC roothub with TT */ + unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ /* glue to PCI and HCD framework */ struct ehci_caps __iomem *caps; @@ -599,13 +599,13 @@ struct ehci_fstn { * needed (mostly in root hub code). */ -#define ehci_is_ARC(e) ((e)->is_arc_rh_tt) +#define ehci_is_TDI(e) ((e)->is_tdi_rh_tt) /* Returns the speed of a device attached to a port on the root hub. */ static inline unsigned int ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) { - if (ehci_is_ARC(ehci)) { + if (ehci_is_TDI(ehci)) { switch ((portsc>>26)&3) { case 0: return 0; @@ -621,7 +621,7 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) #else -#define ehci_is_ARC(e) (0) +#define ehci_is_TDI(e) (0) #define ehci_port_speed(ehci, portsc) (1< Date: Mon, 7 Mar 2005 08:53:47 -0800 Subject: [PATCH] USB: cache the product, manufacturer, and serial number strings at device insertion. This should fix a lot of issues with broken devices that can't handle retrieving strings while they are doing something else (strings would be fetched from usbfs and sysfs entries.) Based on a patch that has been in the SuSE kernel tree for a long time from Olaf Hering Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 24 ++++++------------------ drivers/usb/core/hub.c | 42 ++++++++++++++++++++++++------------------ drivers/usb/core/sysfs.c | 16 ++++++++-------- drivers/usb/core/usb.c | 5 ++++- include/linux/usb.h | 3 +++ 5 files changed, 45 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index a6961efc2cf0..92970d1cd589 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -362,33 +362,21 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb */ static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev) { - char *buf; - if (start > end) return start; - buf = kmalloc(128, GFP_KERNEL); - if (!buf) - return start; - if (dev->descriptor.iManufacturer) { - if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0) - start += sprintf(start, format_string_manufacturer, buf); - } + if (dev->manufacturer) + start += sprintf(start, format_string_manufacturer, dev->manufacturer); if (start > end) goto out; - if (dev->descriptor.iProduct) { - if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0) - start += sprintf(start, format_string_product, buf); - } + if (dev->product) + start += sprintf(start, format_string_product, dev->product); if (start > end) goto out; #ifdef ALLOW_SERIAL_NUMBER - if (dev->descriptor.iSerialNumber) { - if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0) - start += sprintf(start, format_string_serialnumber, buf); - } + if (dev->serial) + start += sprintf(start, format_string_serialnumber, dev->serial); #endif out: - kfree(buf); return start; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c9cad3855744..16348da4e621 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1102,23 +1102,31 @@ static int choose_configuration(struct usb_device *udev) } #ifdef DEBUG -static void show_string(struct usb_device *udev, char *id, int index) +static void show_string(struct usb_device *udev, char *id, char *string) +{ + if (!string) + return; + dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); +} + +#else +static inline void show_string(struct usb_device *udev, char *id, int index) +{} +#endif + +static void get_string(struct usb_device *udev, char **string, int index) { char *buf; if (!index) return; - if (!(buf = kmalloc(256, GFP_KERNEL))) + buf = kmalloc(256, GFP_KERNEL); + if (!buf) return; if (usb_string(udev, index, buf, 256) > 0) - dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, buf); - kfree(buf); + *string = buf; } -#else -static inline void show_string(struct usb_device *udev, char *id, int index) -{} -#endif #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" @@ -1156,22 +1164,20 @@ int usb_new_device(struct usb_device *udev) goto fail; } + /* read the standard strings and cache them if present */ + get_string(udev, &udev->product, udev->descriptor.iProduct); + get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer); + get_string(udev, &udev->serial, udev->descriptor.iSerialNumber); + /* Tell the world! */ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " "SerialNumber=%d\n", udev->descriptor.iManufacturer, udev->descriptor.iProduct, udev->descriptor.iSerialNumber); - - if (udev->descriptor.iProduct) - show_string(udev, "Product", - udev->descriptor.iProduct); - if (udev->descriptor.iManufacturer) - show_string(udev, "Manufacturer", - udev->descriptor.iManufacturer); - if (udev->descriptor.iSerialNumber) - show_string(udev, "SerialNumber", - udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); #ifdef CONFIG_USB_OTG /* diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ce71f7af7478..c41171b1f97c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -89,14 +89,14 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, show_bConfigurationValue, set_bConfigurationValue); /* String fields */ -#define usb_string_attr(name, field) \ +#define usb_string_attr(name) \ static ssize_t show_##name(struct device *dev, char *buf) \ { \ struct usb_device *udev; \ int len; \ \ udev = to_usb_device (dev); \ - len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE); \ + len = snprintf(buf, 256, "%s", udev->name); \ if (len < 0) \ return 0; \ buf[len] = '\n'; \ @@ -105,9 +105,9 @@ static ssize_t show_##name(struct device *dev, char *buf) \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); -usb_string_attr(product, iProduct); -usb_string_attr(manufacturer, iManufacturer); -usb_string_attr(serial, iSerialNumber); +usb_string_attr(product); +usb_string_attr(manufacturer); +usb_string_attr(serial); static ssize_t show_speed (struct device *dev, char *buf) @@ -230,11 +230,11 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) sysfs_create_group(&dev->kobj, &dev_attr_grp); - if (udev->descriptor.iManufacturer) + if (udev->manufacturer) device_create_file (dev, &dev_attr_manufacturer); - if (udev->descriptor.iProduct) + if (udev->product) device_create_file (dev, &dev_attr_product); - if (udev->descriptor.iSerialNumber) + if (udev->serial) device_create_file (dev, &dev_attr_serial); device_create_file (dev, &dev_attr_configuration); } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 99268c2e5164..9fd8b495427f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -647,7 +647,10 @@ static void usb_release_dev(struct device *dev) usb_destroy_configuration(udev); usb_bus_put(udev->bus); - kfree (udev); + kfree(udev->product); + kfree(udev->manufacturer); + kfree(udev->serial); + kfree(udev); } /** diff --git a/include/linux/usb.h b/include/linux/usb.h index 837fadde8d3b..44d1d292c76f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -342,6 +342,9 @@ struct usb_device { int have_langid; /* whether string_langid is valid yet */ int string_langid; /* language ID for strings */ + char *product; + char *manufacturer; + char *serial; /* static strings from the device */ struct list_head filelist; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ -- cgit v1.2.3 From 4ed5e73976cfa2755ee7a972e54fbc2fc610fc44 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Mar 2005 08:54:56 -0800 Subject: [PATCH] USB: make iInterface string cached Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 9 +++++++++ drivers/usb/core/sysfs.c | 39 ++++++++++++++++++--------------------- include/linux/usb.h | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 17a382deaea9..f6b2c309e55d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -988,6 +988,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); + kfree(interface->cur_altsetting->string); + interface->cur_altsetting->string = NULL; device_del (&interface->dev); } @@ -1434,6 +1436,13 @@ free_interfaces: ret); continue; } + if ((intf->cur_altsetting->desc.iInterface) && + (intf->cur_altsetting->string == NULL)) { + intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL); + if (intf->cur_altsetting->string) + usb_string(dev, intf->cur_altsetting->desc.iInterface, + intf->cur_altsetting->string, 256); + } usb_create_sysfs_intf_files (intf); } } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index c41171b1f97c..3f5ae2de70e2 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -272,25 +272,22 @@ usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") -#define usb_intf_str(name, field) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - struct usb_interface *intf; \ - struct usb_device *udev; \ - int len; \ - \ - intf = to_usb_interface (dev); \ - udev = interface_to_usbdev (intf); \ - len = usb_string(udev, intf->cur_altsetting->desc.field, buf, PAGE_SIZE);\ - if (len < 0) \ - return 0; \ - buf[len] = '\n'; \ - buf[len+1] = 0; \ - return len+1; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -usb_intf_str (interface, iInterface); +static ssize_t show_interface_string(struct device *dev, char *buf) +{ + struct usb_interface *intf; + struct usb_device *udev; + int len; + + intf = to_usb_interface (dev); + udev = interface_to_usbdev (intf); + len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); + if (len < 0) + return 0; + buf[len] = '\n'; + buf[len+1] = 0; + return len+1; +} +static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, @@ -309,7 +306,7 @@ void usb_create_sysfs_intf_files (struct usb_interface *intf) { sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); - if (intf->cur_altsetting->desc.iInterface) + if (intf->cur_altsetting->string) device_create_file(&intf->dev, &dev_attr_interface); } @@ -318,7 +315,7 @@ void usb_remove_sysfs_intf_files (struct usb_interface *intf) { sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); - if (intf->cur_altsetting->desc.iInterface) + if (intf->cur_altsetting->string) device_remove_file(&intf->dev, &dev_attr_interface); } diff --git a/include/linux/usb.h b/include/linux/usb.h index 44d1d292c76f..f5ec1f5d8920 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -70,6 +70,7 @@ struct usb_host_interface { */ struct usb_host_endpoint *endpoint; + char *string; /* iInterface string, if present */ unsigned char *extra; /* Extra descriptors */ int extralen; }; -- cgit v1.2.3 From b3bda4b9e513aef5e580c19f98a528260c41c036 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Mar 2005 08:55:16 -0800 Subject: [PATCH] USB: cache the iConfiguration string, if present. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 3 +++ drivers/usb/core/message.c | 7 +++++++ drivers/usb/core/sysfs.c | 37 +++++++++++++++++-------------------- include/linux/usb.h | 3 +++ 4 files changed, 30 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 42e9f8466272..837bad132449 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -420,6 +420,9 @@ void usb_destroy_configuration(struct usb_device *dev) for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { struct usb_host_config *cf = &dev->config[c]; + if (cf->string) + kfree(cf->string); + for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f6b2c309e55d..b4624501cd58 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1413,6 +1413,13 @@ free_interfaces: } kfree(new_interfaces); + if ((cp->desc.iConfiguration) && + (cp->string == NULL)) { + cp->string = kmalloc(256, GFP_KERNEL); + if (cp->string) + usb_string(dev, cp->desc.iConfiguration, cp->string, 256); + } + /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() * routines may install different altsettings and may diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 3f5ae2de70e2..ec9b3bde8ae5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -46,27 +46,24 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") -#define usb_actconfig_str(name, field) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - struct usb_device *udev; \ - struct usb_host_config *actconfig; \ - int len; \ - \ - udev = to_usb_device (dev); \ - actconfig = udev->actconfig; \ - if (!actconfig) \ - return 0; \ - len = usb_string(udev, actconfig->desc.field, buf, PAGE_SIZE); \ - if (len < 0) \ - return 0; \ - buf[len] = '\n'; \ - buf[len+1] = 0; \ - return len+1; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static ssize_t show_configuration_string(struct device *dev, char *buf) +{ + struct usb_device *udev; + struct usb_host_config *actconfig; + int len; -usb_actconfig_str (configuration, iConfiguration) + udev = to_usb_device (dev); + actconfig = udev->actconfig; + if ((!actconfig) || (!actconfig->string)) + return 0; + len = sprintf(buf, actconfig->string, PAGE_SIZE); + if (len < 0) + return 0; + buf[len] = '\n'; + buf[len+1] = 0; + return len+1; +} +static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); /* configuration value is always present, and r/w */ usb_actconfig_show(bConfigurationValue, 1, "%u\n"); diff --git a/include/linux/usb.h b/include/linux/usb.h index f5ec1f5d8920..8d2687ae39ff 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -190,6 +190,8 @@ struct usb_interface_cache { /** * struct usb_host_config - representation of a device's configuration * @desc: the device's configuration descriptor. + * @string: pointer to the cached version of the iConfiguration string, if + * present for this configuration. * @interface: array of pointers to usb_interface structures, one for each * interface in the configuration. The number of interfaces is stored * in desc.bNumInterfaces. These pointers are valid only while the @@ -226,6 +228,7 @@ struct usb_interface_cache { struct usb_host_config { struct usb_config_descriptor desc; + char *string; /* the interfaces associated with this configuration, * stored in no particular order */ struct usb_interface *interface[USB_MAXINTERFACES]; -- cgit v1.2.3 From 40f1626986f711eb7d9b281a6f374b575aa4221c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 7 Mar 2005 09:10:37 -0800 Subject: [PATCH] USB: compat ioctl for submiting URB From: Christopher Li - Let usbdevfs directly handle 32 bit URB ioctl. More specifically: USBDEVFS_SUBMITURB32, USBDEVFS_REAPURB32 and USBDEVFS_REAPURBNDELAY32. Those asynchronous ioctls are too complicate to handle by the compatible layer. Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 251 +++++++++++++++++++++++++++++++------------ fs/compat_ioctl.c | 229 +-------------------------------------- include/linux/compat_ioctl.h | 3 + include/linux/usbdevice_fs.h | 23 +++- 4 files changed, 214 insertions(+), 292 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 547c485e0876..a047bc392983 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -813,9 +813,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) return status; } -static int proc_submiturb(struct dev_state *ps, void __user *arg) + +static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, + struct usbdevfs_iso_packet_desc __user *iso_frame_desc, + void __user *arg) { - struct usbdevfs_urb uurb; struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; struct async *as; @@ -823,42 +825,40 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) unsigned int u, totlen, isofrmlen; int ret, interval = 0, ifnum = -1; - if (copy_from_user(&uurb, arg, sizeof(uurb))) - return -EFAULT; - if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| + if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) return -EINVAL; - if (!uurb.buffer) + if (!uurb->buffer) return -EINVAL; - if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX)) + if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX)) return -EINVAL; - if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { - if ((ifnum = findintfep(ps->dev, uurb.endpoint)) < 0) + if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { + if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0) return ifnum; if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb.endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) + ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; else - ep = ps->dev->ep_out [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK]; + ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; if (!ep) return -ENOENT; - switch(uurb.type) { + switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL) return -EINVAL; /* min 8 byte setup packet, max arbitrary */ - if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE) + if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE) return -EINVAL; if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) return -ENOMEM; - if (copy_from_user(dr, uurb.buffer, 8)) { + if (copy_from_user(dr, uurb->buffer, 8)) { kfree(dr); return -EFAULT; } - if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { + if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { kfree(dr); return -EINVAL; } @@ -866,11 +866,11 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) kfree(dr); return ret; } - uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); - uurb.number_of_packets = 0; - uurb.buffer_length = le16_to_cpup(&dr->wLength); - uurb.buffer += 8; - if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) { + uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); + uurb->number_of_packets = 0; + uurb->buffer_length = le16_to_cpup(&dr->wLength); + uurb->buffer += 8; + if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } @@ -883,29 +883,29 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) return -EINVAL; /* allow single-shot interrupt transfers, at bogus rates */ } - uurb.number_of_packets = 0; - if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) + uurb->number_of_packets = 0; + if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) + if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; break; case USBDEVFS_URB_TYPE_ISO: /* arbitrary limit */ - if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128) + if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) return -EINVAL; interval = 1 << min (15, ep->desc.bInterval - 1); - isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets; + isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; - if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) { + if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { kfree(isopkt); return -EFAULT; } - for (totlen = u = 0; u < uurb.number_of_packets; u++) { + for (totlen = u = 0; u < uurb->number_of_packets; u++) { if (isopkt[u].length > 1023) { kfree(isopkt); return -EINVAL; @@ -916,11 +916,11 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) kfree(isopkt); return -EINVAL; } - uurb.buffer_length = totlen; + uurb->buffer_length = totlen; break; case USBDEVFS_URB_TYPE_INTERRUPT: - uurb.number_of_packets = 0; + uurb->number_of_packets = 0; if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -EINVAL; @@ -928,23 +928,23 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) interval = 1 << min (15, ep->desc.bInterval - 1); else interval = ep->desc.bInterval; - if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) + if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) + if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; break; default: return -EINVAL; } - if (!(as = alloc_async(uurb.number_of_packets))) { + if (!(as = alloc_async(uurb->number_of_packets))) { if (isopkt) kfree(isopkt); if (dr) kfree(dr); return -ENOMEM; } - if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) { + if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) { if (isopkt) kfree(isopkt); if (dr) @@ -953,16 +953,16 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb.flags; - as->urb->transfer_buffer_length = uurb.buffer_length; + as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags; + as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; - as->urb->start_frame = uurb.start_frame; - as->urb->number_of_packets = uurb.number_of_packets; + as->urb->start_frame = uurb->start_frame; + as->urb->number_of_packets = uurb->number_of_packets; as->urb->interval = interval; as->urb->context = as; as->urb->complete = async_completed; - for (totlen = u = 0; u < uurb.number_of_packets; u++) { + for (totlen = u = 0; u < uurb->number_of_packets; u++) { as->urb->iso_frame_desc[u].offset = totlen; as->urb->iso_frame_desc[u].length = isopkt[u].length; totlen += isopkt[u].length; @@ -971,15 +971,15 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) kfree(isopkt); as->ps = ps; as->userurb = arg; - if (uurb.endpoint & USB_DIR_IN) - as->userbuffer = uurb.buffer; + if (uurb->endpoint & USB_DIR_IN) + as->userbuffer = uurb->buffer; else as->userbuffer = NULL; - as->signr = uurb.signr; + as->signr = uurb->signr; as->ifnum = ifnum; as->task = current; - if (!(uurb.endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) { + if (!(uurb->endpoint & USB_DIR_IN)) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } @@ -994,6 +994,16 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) return 0; } +static int proc_submiturb(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_urb uurb; + + if (copy_from_user(&uurb, arg, sizeof(uurb))) + return -EFAULT; + + return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); +} + static int proc_unlinkurb(struct dev_state *ps, void __user *arg) { struct async *as; @@ -1005,10 +1015,11 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg) return 0; } -static int processcompl(struct async *as) +static int processcompl(struct async *as, void __user * __user *arg) { struct urb *urb = as->urb; struct usbdevfs_urb __user *userurb = as->userurb; + void __user *addr = as->userurb; unsigned int i; if (as->userbuffer) @@ -1031,16 +1042,19 @@ static int processcompl(struct async *as) &userurb->iso_frame_desc[i].status)) return -EFAULT; } + + free_async(as); + + if (put_user(addr, (void __user * __user *)arg)) + return -EFAULT; return 0; } -static int proc_reapurb(struct dev_state *ps, void __user *arg) +static struct async* reap_as(struct dev_state *ps) { DECLARE_WAITQUEUE(wait, current); struct async *as = NULL; - void __user *addr; struct usb_device *dev = ps->dev; - int ret; add_wait_queue(&ps->wait, &wait); for (;;) { @@ -1055,16 +1069,14 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); - if (as) { - ret = processcompl(as); - addr = as->userurb; - free_async(as); - if (ret) - return ret; - if (put_user(addr, (void __user * __user *)arg)) - return -EFAULT; - return 0; - } + return as; +} + +static int proc_reapurb(struct dev_state *ps, void __user *arg) +{ + struct async *as = reap_as(ps); + if (as) + return processcompl(as, (void __user * __user *)arg); if (signal_pending(current)) return -EINTR; return -EIO; @@ -1073,21 +1085,107 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) { struct async *as; - void __user *addr; - int ret; if (!(as = async_getcompleted(ps))) return -EAGAIN; - ret = processcompl(as); - addr = as->userurb; + return processcompl(as, (void __user * __user *)arg); +} + +#ifdef CONFIG_COMPAT + +static int get_urb32(struct usbdevfs_urb *kurb, + struct usbdevfs_urb32 __user *uurb) +{ + __u32 uptr; + if (get_user(kurb->type, &uurb->type) || + __get_user(kurb->endpoint, &uurb->endpoint) || + __get_user(kurb->status, &uurb->status) || + __get_user(kurb->flags, &uurb->flags) || + __get_user(kurb->buffer_length, &uurb->buffer_length) || + __get_user(kurb->actual_length, &uurb->actual_length) || + __get_user(kurb->start_frame, &uurb->start_frame) || + __get_user(kurb->number_of_packets, &uurb->number_of_packets) || + __get_user(kurb->error_count, &uurb->error_count) || + __get_user(kurb->signr, &uurb->signr)) + return -EFAULT; + + if (__get_user(uptr, &uurb->buffer)) + return -EFAULT; + kurb->buffer = compat_ptr(uptr); + if (__get_user(uptr, &uurb->buffer)) + return -EFAULT; + kurb->usercontext = compat_ptr(uptr); + + return 0; +} + +static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_urb uurb; + + if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) + return -EFAULT; + + return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb __user *)arg)->iso_frame_desc, arg); +} + +static int processcompl_compat(struct async *as, void __user * __user *arg) +{ + struct urb *urb = as->urb; + struct usbdevfs_urb32 __user *userurb = as->userurb; + void __user *addr = as->userurb; + unsigned int i; + + if (as->userbuffer) + if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) + return -EFAULT; + if (put_user(urb->status, &userurb->status)) + return -EFAULT; + if (put_user(urb->actual_length, &userurb->actual_length)) + return -EFAULT; + if (put_user(urb->error_count, &userurb->error_count)) + return -EFAULT; + + if (!(usb_pipeisoc(urb->pipe))) + return 0; + for (i = 0; i < urb->number_of_packets; i++) { + if (put_user(urb->iso_frame_desc[i].actual_length, + &userurb->iso_frame_desc[i].actual_length)) + return -EFAULT; + if (put_user(urb->iso_frame_desc[i].status, + &userurb->iso_frame_desc[i].status)) + return -EFAULT; + } + free_async(as); - if (ret) - return ret; - if (put_user(addr, (void __user * __user *)arg)) + if (put_user((u32)(u64)addr, (u32 __user *)arg)) return -EFAULT; return 0; } +static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) +{ + struct async *as = reap_as(ps); + if (as) + return processcompl_compat(as, (void __user * __user *)arg); + if (signal_pending(current)) + return -EINTR; + return -EIO; +} + +static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) +{ + struct async *as; + + printk("reapurbnblock\n"); + if (!(as = async_getcompleted(ps))) + return -EAGAIN; + printk("reap got as %p\n", as); + return processcompl_compat(as, (void __user * __user *)arg); +} + +#endif + static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) { struct usbdevfs_disconnectsignal ds; @@ -1299,6 +1397,27 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd inode->i_mtime = CURRENT_TIME; break; +#ifdef CONFIG_COMPAT + + case USBDEVFS_SUBMITURB32: + snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__); + ret = proc_submiturb_compat(ps, p); + if (ret >= 0) + inode->i_mtime = CURRENT_TIME; + break; + + case USBDEVFS_REAPURB32: + snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__); + ret = proc_reapurb_compat(ps, p); + break; + + case USBDEVFS_REAPURBNDELAY32: + snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__); + ret = proc_reapurbnonblock_compat(ps, p); + break; + +#endif + case USBDEVFS_DISCARDURB: snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); ret = proc_unlinkurb(ps, p); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a14dc212e301..db23d05df174 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2575,229 +2575,11 @@ static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p); } -/* This needs more work before we can enable it. Unfortunately - * because of the fancy asynchronous way URB status/error is written - * back to userspace, we'll need to fiddle with USB devio internals - * and/or reimplement entirely the frontend of it ourselves. -DaveM - * - * The issue is: - * - * When an URB is submitted via usbdevicefs it is put onto an - * asynchronous queue. When the URB completes, it may be reaped - * via another ioctl. During this reaping the status is written - * back to userspace along with the length of the transfer. - * - * We must translate into 64-bit kernel types so we pass in a kernel - * space copy of the usbdevfs_urb structure. This would mean that we - * must do something to deal with the async entry reaping. First we - * have to deal somehow with this transitory memory we've allocated. - * This is problematic since there are many call sites from which the - * async entries can be destroyed (and thus when we'd need to free up - * this kernel memory). One of which is the close() op of usbdevicefs. - * To handle that we'd need to make our own file_operations struct which - * overrides usbdevicefs's release op with our own which runs usbdevicefs's - * real release op then frees up the kernel memory. - * - * But how to keep track of these kernel buffers? We'd need to either - * keep track of them in some table _or_ know about usbdevicefs internals - * (ie. the exact layout of its file private, which is actually defined - * in linux/usbdevice_fs.h, the layout of the async queues are private to - * devio.c) - * - * There is one possible other solution I considered, also involving knowledge - * of usbdevicefs internals: - * - * After an URB is submitted, we "fix up" the address back to the user - * space one. This would work if the status/length fields written back - * by the async URB completion lines up perfectly in the 32-bit type with - * the 64-bit kernel type. Unfortunately, it does not because the iso - * frame descriptors, at the end of the struct, can be written back. - * - * I think we'll just need to simply duplicate the devio URB engine here. - */ -#if 0 -struct usbdevfs_urb32 { - unsigned char type; - unsigned char endpoint; - compat_int_t status; - compat_uint_t flags; - compat_caddr_t buffer; - compat_int_t buffer_length; - compat_int_t actual_length; - compat_int_t start_frame; - compat_int_t number_of_packets; - compat_int_t error_count; - compat_uint_t signr; - compat_caddr_t usercontext; /* unused */ - struct usbdevfs_iso_packet_desc iso_frame_desc[0]; -}; - -#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) - -static int get_urb32(struct usbdevfs_urb *kurb, - struct usbdevfs_urb32 *uurb) -{ - if (get_user(kurb->type, &uurb->type) || - __get_user(kurb->endpoint, &uurb->endpoint) || - __get_user(kurb->status, &uurb->status) || - __get_user(kurb->flags, &uurb->flags) || - __get_user(kurb->buffer_length, &uurb->buffer_length) || - __get_user(kurb->actual_length, &uurb->actual_length) || - __get_user(kurb->start_frame, &uurb->start_frame) || - __get_user(kurb->number_of_packets, &uurb->number_of_packets) || - __get_user(kurb->error_count, &uurb->error_count) || - __get_user(kurb->signr, &uurb->signr)) - return -EFAULT; - - kurb->usercontext = 0; /* unused currently */ - - return 0; -} - -/* Just put back the values which usbdevfs actually changes. */ -static int put_urb32(struct usbdevfs_urb *kurb, - struct usbdevfs_urb32 *uurb) -{ - if (put_user(kurb->status, &uurb->status) || - __put_user(kurb->actual_length, &uurb->actual_length) || - __put_user(kurb->error_count, &uurb->error_count)) - return -EFAULT; - - if (kurb->number_of_packets != 0) { - int i; - - for (i = 0; i < kurb->number_of_packets; i++) { - if (__put_user(kurb->iso_frame_desc[i].actual_length, - &uurb->iso_frame_desc[i].actual_length) || - __put_user(kurb->iso_frame_desc[i].status, - &uurb->iso_frame_desc[i].status)) - return -EFAULT; - } - } - - return 0; -} - -static int get_urb32_isoframes(struct usbdevfs_urb *kurb, - struct usbdevfs_urb32 *uurb) -{ - unsigned int totlen; - int i; - - if (kurb->type != USBDEVFS_URB_TYPE_ISO) { - kurb->number_of_packets = 0; - return 0; - } - - if (kurb->number_of_packets < 1 || - kurb->number_of_packets > 128) - return -EINVAL; - - if (copy_from_user(&kurb->iso_frame_desc[0], - &uurb->iso_frame_desc[0], - sizeof(struct usbdevfs_iso_packet_desc) * - kurb->number_of_packets)) - return -EFAULT; - - totlen = 0; - for (i = 0; i < kurb->number_of_packets; i++) { - unsigned int this_len; - - this_len = kurb->iso_frame_desc[i].length; - if (this_len > 1023) - return -EINVAL; - - totlen += this_len; - } - - if (totlen > 32768) - return -EINVAL; - - kurb->buffer_length = totlen; - - return 0; -} - -static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct usbdevfs_urb *kurb; - struct usbdevfs_urb32 *uurb; - mm_segment_t old_fs; - __u32 udata; - void *uptr, *kptr; - unsigned int buflen; - int err; - - uurb = compat_ptr(arg); - - err = -ENOMEM; - kurb = kmalloc(sizeof(struct usbdevfs_urb) + - (sizeof(struct usbdevfs_iso_packet_desc) * 128), - GFP_KERNEL); - if (!kurb) - goto out; - - err = -EFAULT; - if (get_urb32(kurb, uurb)) - goto out; - - err = get_urb32_isoframes(kurb, uurb); - if (err) - goto out; - - err = -EFAULT; - if (__get_user(udata, &uurb->buffer)) - goto out; - uptr = compat_ptr(udata); - - buflen = kurb->buffer_length; - err = verify_area(VERIFY_WRITE, uptr, buflen); - if (err) - goto out; - - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb); - set_fs(old_fs); - if (err >= 0) { - /* RED-PEN Shit, this doesn't work for async URBs :-( XXX */ - if (put_urb32(kurb, uurb)) { - err = -EFAULT; - } - } - -out: - kfree(kurb); - return err; -} -#endif - -#define USBDEVFS_REAPURB32 _IOW('U', 12, u32) -#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32) - -static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs; - void *kptr; - int err; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_ioctl(fd, - (cmd == USBDEVFS_REAPURB32 ? - USBDEVFS_REAPURB : - USBDEVFS_REAPURBNDELAY), - (unsigned long) &kptr); - set_fs(old_fs); - - if (err >= 0 && - put_user((u32)(u64)kptr, (u32 __user *)compat_ptr(arg))) - err = -EFAULT; - - return err; -} +/* + * USBDEVFS_SUBMITURB, USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY + * are handled in usbdevfs core. -Christopher Li + */ struct usbdevfs_disconnectsignal32 { compat_int_t signr; @@ -3331,9 +3113,6 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl) /* Usbdevfs */ HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control) HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk) -/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/ -HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb) -HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb) HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) /* i2c */ HANDLE_IOCTL(I2C_FUNCS, w_long) diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 383275bf924e..19f15d807ba5 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -692,6 +692,9 @@ COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE) COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO) COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO) COMPATIBLE_IOCTL(USBDEVFS_RESET) +COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32) +COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) +COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) /* MTD */ COMPATIBLE_IOCTL(MEMGETINFO) diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index aed8193eb420..fb57c2217468 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -32,6 +32,7 @@ #define _LINUX_USBDEVICE_FS_H #include +#include /* --------------------------------------------------------------------- */ @@ -123,6 +124,24 @@ struct usbdevfs_hub_portinfo { char port [127]; /* e.g. port 3 connects to device 27 */ }; +#ifdef CONFIG_COMPAT +struct usbdevfs_urb32 { + unsigned char type; + unsigned char endpoint; + compat_int_t status; + compat_uint_t flags; + compat_caddr_t buffer; + compat_int_t buffer_length; + compat_int_t actual_length; + compat_int_t start_frame; + compat_int_t number_of_packets; + compat_int_t error_count; + compat_uint_t signr; + compat_caddr_t usercontext; /* unused */ + struct usbdevfs_iso_packet_desc iso_frame_desc[0]; +}; +#endif + #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) #define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer) #define USBDEVFS_RESETEP _IOR('U', 3, unsigned int) @@ -130,9 +149,12 @@ struct usbdevfs_hub_portinfo { #define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int) #define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver) #define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb) +#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) #define USBDEVFS_DISCARDURB _IO('U', 11) #define USBDEVFS_REAPURB _IOW('U', 12, void *) +#define USBDEVFS_REAPURB32 _IOW('U', 12, u32) #define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *) +#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32) #define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal) #define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int) #define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) @@ -143,5 +165,4 @@ struct usbdevfs_hub_portinfo { #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) #define USBDEVFS_DISCONNECT _IO('U', 22) #define USBDEVFS_CONNECT _IO('U', 23) - #endif /* _LINUX_USBDEVICE_FS_H */ -- cgit v1.2.3 From d364e1899ceda638bd3e0d59c44a901bd60ff91b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 8 Mar 2005 22:37:20 +0000 Subject: [ARM PATCH] 2517/1: more ixp2000 typo fixes Patch from Lennert Buytenhek Another round of ixp2000 typo fixes. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- Documentation/arm/IXP2000 | 2 +- arch/arm/mach-ixp2000/enp2611.c | 2 +- arch/arm/mach-ixp2000/ixdp2x01.c | 2 +- include/asm-arm/arch-ixp2000/io.h | 2 +- include/asm-arm/arch-ixp2000/ixdp2x01.h | 2 +- include/asm-arm/arch-ixp2000/platform.h | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000 index 969f165932f2..e0148b6b2c40 100644 --- a/Documentation/arm/IXP2000 +++ b/Documentation/arm/IXP2000 @@ -45,7 +45,7 @@ MAILING LISTS REGARDING THE INTEL SDK. 4. Usage Notes -- The IXP2000 platforms ususally have rather complex PCI bus topologies +- The IXP2000 platforms usually have rather complex PCI bus topologies with large memory space requirements. In addition, b/c of the way the Intel SDK is designed, devices are enumerated in a very specific way. B/c of this this, we use "pci=firmware" option in the kernel diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index e4d2992d9427..b51b9a58eecf 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -6,7 +6,7 @@ * Created 2004 by Lennert Buytenhek from the ixdp2x01 code. The * original version carries the following notices: * - * Original Author: Andrzej Mialwoski + * Original Author: Andrzej Mialkowski * Maintainer: Deepak Saxena * * Copyright (C) 2002-2003 Intel Corp. diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index 0e919bbf9d92..e94dace3d412 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -3,7 +3,7 @@ * * Code common to Intel IXDP2401 and IXDP2801 platforms * - * Original Author: Andrzej Mialwoski + * Original Author: Andrzej Mialkowski * Maintainer: Deepak Saxena * * Copyright (C) 2002-2003 Intel Corp. diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h index 571dbbcd8521..4555265cf5ce 100644 --- a/include/asm-arm/arch-ixp2000/io.h +++ b/include/asm-arm/arch-ixp2000/io.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-ixdp2000/io.h + * linux/include/asm-arm/arch-ixp2000/io.h * * Original Author: Naeem M Afzal * Maintainer: Deepak Saxena diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h index 9e1672cd84cf..b3a1bcda8d01 100644 --- a/include/asm-arm/arch-ixp2000/ixdp2x01.h +++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h @@ -1,5 +1,5 @@ /* - * include/asm/arch/ixdp2x01.h + * include/asm-arm/arch-ixp2000/ixdp2x01.h * * Platform definitions for IXDP2X01 && IXDP2801 systems * diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index 16e4a240199d..7118a843ab12 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -1,5 +1,5 @@ /* - * include/asm-arh/arch-ixp2000/platform.h + * include/asm-arm/arch-ixp2000/platform.h * * Various bits of code used by platform-level code. * @@ -50,7 +50,7 @@ static inline void ixp2000_reg_write(volatile unsigned long *reg, unsigned long * Boards may multiplex different devices on the 2nd channel of * the slowport interface that each need different configuration * settings. For example, the IXDP2400 uses channel 2 on the interface - * to access the CPLD, the switch fabric card, and te media card. Each + * to access the CPLD, the switch fabric card, and the media card. Each * one needs a different mode so drivers must save/restore the mode * before and after each operation. * -- cgit v1.2.3 From deecd43353bb49ae8f97a483d2659798130044fa Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Tue, 8 Mar 2005 22:47:59 +0000 Subject: [ARM PATCH] 2522/1: Sharp SCOOP - Add mutliple device support Patch from Richard Purdie Sharp SCOOP: Devices with multiple scoop interfaces are now available so: * add support for mutliple device support to the driver * Update corgi, collie and poodle to share the scoop device structure so a device can be selected in drivers * Update drivers to use the device structures Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/common/scoop.c | 116 +++++++++++++++++++++++++------------ arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-sa1100/collie.c | 2 +- drivers/pcmcia/pxa2xx_sharpsl.c | 40 ++++++------- drivers/video/backlight/corgi_bl.c | 4 +- include/asm-arm/arch-pxa/corgi.h | 4 ++ include/asm-arm/hardware/scoop.h | 10 ++-- 8 files changed, 113 insertions(+), 67 deletions(-) (limited to 'include') diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 811c55498280..cfd0d3e550d9 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -15,47 +15,52 @@ #include #include -static void __iomem *scoop_io_base; +#define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr))) -#define SCOOP_REG(adr) (*(volatile unsigned short*)(scoop_io_base+(adr))) +struct scoop_dev { + void *base; + spinlock_t scoop_lock; + u32 scoop_gpwr; +}; -void reset_scoop(void) +void reset_scoop(struct device *dev) { - SCOOP_REG(SCOOP_MCR) = 0x0100; // 00 - SCOOP_REG(SCOOP_CDR) = 0x0000; // 04 - SCOOP_REG(SCOOP_CPR) = 0x0000; // 0C - SCOOP_REG(SCOOP_CCR) = 0x0000; // 10 - SCOOP_REG(SCOOP_IMR) = 0x0000; // 18 - SCOOP_REG(SCOOP_IRM) = 0x00FF; // 14 - SCOOP_REG(SCOOP_ISR) = 0x0000; // 1C - SCOOP_REG(SCOOP_IRM) = 0x0000; + struct scoop_dev *sdev = dev_get_drvdata(dev); + + SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100; // 00 + SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000; // 04 + SCOOP_REG(sdev->base,SCOOP_CPR) = 0x0000; // 0C + SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000; // 10 + SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000; // 18 + SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF; // 14 + SCOOP_REG(sdev->base,SCOOP_ISR) = 0x0000; // 1C + SCOOP_REG(sdev->base,SCOOP_IRM) = 0x0000; } -static DEFINE_SPINLOCK(scoop_lock); -static u32 scoop_gpwr; - -unsigned short set_scoop_gpio(unsigned short bit) +unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) { unsigned short gpio_bit; unsigned long flag; + struct scoop_dev *sdev = dev_get_drvdata(dev); - spin_lock_irqsave(&scoop_lock, flag); - gpio_bit = SCOOP_REG(SCOOP_GPWR) | bit; - SCOOP_REG(SCOOP_GPWR) = gpio_bit; - spin_unlock_irqrestore(&scoop_lock, flag); + spin_lock_irqsave(&sdev->scoop_lock, flag); + gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) | bit; + SCOOP_REG(sdev->base, SCOOP_GPWR) = gpio_bit; + spin_unlock_irqrestore(&sdev->scoop_lock, flag); return gpio_bit; } -unsigned short reset_scoop_gpio(unsigned short bit) +unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) { unsigned short gpio_bit; unsigned long flag; + struct scoop_dev *sdev = dev_get_drvdata(dev); - spin_lock_irqsave(&scoop_lock, flag); - gpio_bit = SCOOP_REG(SCOOP_GPWR) & ~bit; - SCOOP_REG(SCOOP_GPWR) = gpio_bit; - spin_unlock_irqrestore(&scoop_lock, flag); + spin_lock_irqsave(&sdev->scoop_lock, flag); + gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) & ~bit; + SCOOP_REG(sdev->base,SCOOP_GPWR) = gpio_bit; + spin_unlock_irqrestore(&sdev->scoop_lock, flag); return gpio_bit; } @@ -63,25 +68,30 @@ unsigned short reset_scoop_gpio(unsigned short bit) EXPORT_SYMBOL(set_scoop_gpio); EXPORT_SYMBOL(reset_scoop_gpio); -unsigned short read_scoop_reg(unsigned short reg) +unsigned short read_scoop_reg(struct device *dev, unsigned short reg) { - return SCOOP_REG(reg); + struct scoop_dev *sdev = dev_get_drvdata(dev); + return SCOOP_REG(sdev->base,reg); } -void write_scoop_reg(unsigned short reg, unsigned short data) +void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data) { - SCOOP_REG(reg)=data; + struct scoop_dev *sdev = dev_get_drvdata(dev); + SCOOP_REG(sdev->base,reg)=data; } EXPORT_SYMBOL(reset_scoop); EXPORT_SYMBOL(read_scoop_reg); EXPORT_SYMBOL(write_scoop_reg); +#ifdef CONFIG_PM static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level) { if (level == SUSPEND_POWER_DOWN) { - scoop_gpwr = SCOOP_REG(SCOOP_GPWR); - SCOOP_REG(SCOOP_GPWR) = 0; + struct scoop_dev *sdev = dev_get_drvdata(dev); + + sdev->scoop_gpwr = SCOOP_REG(sdev->base,SCOOP_GPWR); + SCOOP_REG(sdev->base,SCOOP_GPWR) = 0; } return 0; } @@ -89,13 +99,20 @@ static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level) static int scoop_resume(struct device *dev, uint32_t level) { if (level == RESUME_POWER_ON) { - SCOOP_REG(SCOOP_GPWR) = scoop_gpwr; + struct scoop_dev *sdev = dev_get_drvdata(dev); + + SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr; } return 0; } +#else +#define scoop_suspend NULL +#define scoop_resume NULL +#endif int __init scoop_probe(struct device *dev) { + struct scoop_dev *devptr; struct scoop_config *inf; struct platform_device *pdev = to_platform_device(dev); struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -103,25 +120,50 @@ int __init scoop_probe(struct device *dev) if (!mem) return -EINVAL; + devptr = kmalloc(sizeof(struct scoop_dev), GFP_KERNEL); + + if (!devptr) + return -ENOMEM; + + memset(devptr, 0, sizeof(struct scoop_dev)); + spin_lock_init(&devptr->scoop_lock); + inf = dev->platform_data; - scoop_io_base = ioremap(mem->start, 0x1000); - if (!scoop_io_base) + devptr->base = ioremap(mem->start, mem->end - mem->start + 1); + + if (!devptr->base) { + kfree(devptr); return -ENOMEM; + } - SCOOP_REG(SCOOP_MCR) = 0x0140; + dev_set_drvdata(dev, devptr); - reset_scoop(); + printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base); - SCOOP_REG(SCOOP_GPCR) = inf->io_dir & 0xffff; - SCOOP_REG(SCOOP_GPWR) = inf->io_out & 0xffff; + SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140; + reset_scoop(dev); + SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff; + SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff; return 0; } +static int scoop_remove(struct device *dev) +{ + struct scoop_dev *sdev = dev_get_drvdata(dev); + if (sdev) { + iounmap(sdev->base); + kfree(sdev); + dev_set_drvdata(dev, NULL); + } + return 0; +} + static struct device_driver scoop_driver = { .name = "sharp-scoop", .bus = &platform_bus_type, .probe = scoop_probe, + .remove = scoop_remove, .suspend = scoop_suspend, .resume = scoop_resume, }; diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 5260436cdb3b..94841068a688 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -59,7 +59,7 @@ static struct scoop_config corgi_scoop_setup = { .io_out = CORGI_SCOOP_IO_OUT, }; -static struct platform_device corgiscoop_device = { +struct platform_device corgiscoop_device = { .name = "sharp-scoop", .id = -1, .dev = { diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index d49bc5814022..5ee67808224a 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -51,7 +51,7 @@ static struct scoop_config poodle_scoop_setup = { .io_out = POODLE_SCOOP_IO_OUT, }; -static struct platform_device poodle_scoop_device = { +struct platform_device poodle_scoop_device = { .name = "sharp-scoop", .id = -1, .dev = { diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 2bc071a7b7f3..da9412c5d385 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -55,7 +55,7 @@ static struct scoop_config collie_scoop_setup = { .io_out = COLLIE_SCOOP_IO_OUT, }; -static struct platform_device colliescoop_device = { +struct platform_device colliescoop_device = { .name = "sharp-scoop", .id = -1, .dev = { diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index cabb91fff0d9..42efe218867a 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -38,7 +38,7 @@ static struct pcmcia_irqs irqs[] = { static void sharpsl_pcmcia_init_reset(void) { - reset_scoop(); + reset_scoop(&corgiscoop_device.dev); keep_vs = NO_KEEP_VS; keep_rd = 0; } @@ -79,8 +79,8 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } /* Enable interrupt */ - write_scoop_reg(SCOOP_IMR, 0x00C0); - write_scoop_reg(SCOOP_MCR, 0x0101); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); keep_vs = NO_KEEP_VS; skt->irq = CORGI_IRQ_GPIO_CF_IRQ; @@ -102,30 +102,30 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, { unsigned short cpr, csr; - cpr = read_scoop_reg(SCOOP_CPR); + cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); - write_scoop_reg(SCOOP_IRM, 0x00FF); - write_scoop_reg(SCOOP_ISR, 0x0000); - write_scoop_reg(SCOOP_IRM, 0x0000); - csr = read_scoop_reg(SCOOP_CSR); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); + csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); if (csr & 0x0004) { /* card eject */ - write_scoop_reg(SCOOP_CDR, 0x0000); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); keep_vs = NO_KEEP_VS; } else if (!(keep_vs & NO_KEEP_VS)) { /* keep vs1,vs2 */ - write_scoop_reg(SCOOP_CDR, 0x0000); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); csr |= keep_vs; } else if (cpr & 0x0003) { /* power on */ - write_scoop_reg(SCOOP_CDR, 0x0000); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); keep_vs = (csr & 0x00C0); } else { /* card detect */ - write_scoop_reg(SCOOP_CDR, 0x0002); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); } state->detect = (csr & 0x0004) ? 0 : 1; @@ -166,10 +166,10 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, local_irq_save(flags); - nmcr = (mcr = read_scoop_reg(SCOOP_MCR)) & ~0x0010; - ncpr = (cpr = read_scoop_reg(SCOOP_CPR)) & ~0x0083; - nccr = (ccr = read_scoop_reg(SCOOP_CCR)) & ~0x0080; - nimr = (imr = read_scoop_reg(SCOOP_IMR)) & ~0x003E; + nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; + ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; + nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; + nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; ncpr |= (state->Vcc == 33) ? 0x0001 : (state->Vcc == 50) ? 0x0002 : 0; @@ -193,13 +193,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, } if (mcr != nmcr) - write_scoop_reg(SCOOP_MCR, nmcr); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); if (cpr != ncpr) - write_scoop_reg(SCOOP_CPR, ncpr); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); if (ccr != nccr) - write_scoop_reg(SCOOP_CCR, nccr); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); if (imr != nimr) - write_scoop_reg(SCOOP_IMR, nimr); + write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); local_irq_restore(flags); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index b54ec447725d..3c026b036c86 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -52,9 +52,9 @@ static void corgibl_send_intensity(int intensity) corgi_ssp_blduty_set(intensity & 0x1f); /* Bit 5 is via SCOOP */ if (intensity & 0x0020) - set_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT); + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); else - reset_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT); + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); spin_unlock_irqrestore(&bl_lock, flags); } diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h index 950c9378a6a6..4f69467327d1 100644 --- a/include/asm-arm/arch-pxa/corgi.h +++ b/include/asm-arm/arch-pxa/corgi.h @@ -133,6 +133,10 @@ struct sharpsl_flash_param_info { unsigned int phadadj; }; +/* + * Shared data structures + */ +extern struct platform_device corgiscoop_device; /* * External Functions diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h index 669b7df6e570..7ea771ff6144 100644 --- a/include/asm-arm/hardware/scoop.h +++ b/include/asm-arm/hardware/scoop.h @@ -40,8 +40,8 @@ struct scoop_config { unsigned short io_dir; }; -void reset_scoop(void); -unsigned short set_scoop_gpio(unsigned short bit); -unsigned short reset_scoop_gpio(unsigned short bit); -unsigned short read_scoop_reg(unsigned short reg); -void write_scoop_reg(unsigned short reg, unsigned short data); +void reset_scoop(struct device *dev); +unsigned short set_scoop_gpio(struct device *dev, unsigned short bit); +unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit); +unsigned short read_scoop_reg(struct device *dev, unsigned short reg); +void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data); -- cgit v1.2.3 From 7f93f6dd3bb43e0ee32a3edf496fb84f74a51ce8 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Mar 2005 16:12:28 -0800 Subject: [PATCH] Sparse annotations and cleanup warnings for PA-RISC - Missing UL on large integers - 0/NULL confusion - __user annotations - C99-style array elements Signed-off-by: Randolph Chung Signed-off-by: Matthew Wilcox Signed-off-by: Linus Torvalds --- arch/parisc/kernel/firmware.c | 6 ++-- arch/parisc/kernel/hardware.c | 24 +++++++------- arch/parisc/kernel/ioctl32.c | 2 +- arch/parisc/kernel/perf.c | 56 +++++++++++++++---------------- arch/parisc/kernel/process.c | 8 ++--- arch/parisc/kernel/setup.c | 6 ++-- arch/parisc/kernel/signal.c | 30 ++++++++--------- arch/parisc/kernel/signal32.c | 26 +++++++-------- arch/parisc/kernel/signal32.h | 12 +++---- arch/parisc/kernel/sys_parisc.c | 16 ++++----- arch/parisc/kernel/sys_parisc32.c | 70 +++++++++++++++++++-------------------- arch/parisc/kernel/traps.c | 18 +++++----- arch/parisc/kernel/unaligned.c | 4 +-- arch/parisc/lib/checksum.c | 6 ++-- arch/parisc/math-emu/driver.c | 2 +- arch/parisc/mm/fault.c | 2 +- include/asm-parisc/checksum.h | 4 +-- include/asm-parisc/compat.h | 8 ++--- include/asm-parisc/signal.h | 7 ++-- 19 files changed, 153 insertions(+), 154 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index e8b722d25aaf..a836945c8b7d 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -120,10 +120,10 @@ static unsigned long f_extend(unsigned long address) #ifdef __LP64__ if(unlikely(parisc_narrow_firmware)) { if((address & 0xff000000) == 0xf0000000) - return 0xf0f0f0f000000000 | (u32)address; + return 0xf0f0f0f000000000UL | (u32)address; if((address & 0xf0000000) == 0xf0000000) - return 0xffffffff00000000 | (u32)address; + return 0xffffffff00000000UL | (u32)address; } #endif return address; @@ -912,7 +912,7 @@ int pdc_do_firm_test_reset(unsigned long ftc_bitmap) * * Reset the system. */ -int pdc_do_reset() +int pdc_do_reset(void) { int retval; diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c index 4abd43910db6..2071b5bba15c 100644 --- a/arch/parisc/kernel/hardware.c +++ b/arch/parisc/kernel/hardware.c @@ -1296,18 +1296,18 @@ static struct hp_cpu_type_mask { }; char *cpu_name_version[][2] = { - [pcx] { "PA7000 (PCX)", "1.0" }, - [pcxs] { "PA7000 (PCX-S)", "1.1a" }, - [pcxt] { "PA7100 (PCX-T)", "1.1b" }, - [pcxt_] { "PA7200 (PCX-T')", "1.1c" }, - [pcxl] { "PA7100LC (PCX-L)", "1.1d" }, - [pcxl2] { "PA7300LC (PCX-L2)", "1.1e" }, - [pcxu] { "PA8000 (PCX-U)", "2.0" }, - [pcxu_] { "PA8200 (PCX-U+)", "2.0" }, - [pcxw] { "PA8500 (PCX-W)", "2.0" }, - [pcxw_] { "PA8600 (PCX-W+)", "2.0" }, - [pcxw2] { "PA8700 (PCX-W2)", "2.0" }, - [mako] { "PA8800 (Mako)", "2.0" } + [pcx] = { "PA7000 (PCX)", "1.0" }, + [pcxs] = { "PA7000 (PCX-S)", "1.1a" }, + [pcxt] = { "PA7100 (PCX-T)", "1.1b" }, + [pcxt_] = { "PA7200 (PCX-T')", "1.1c" }, + [pcxl] = { "PA7100LC (PCX-L)", "1.1d" }, + [pcxl2] = { "PA7300LC (PCX-L2)", "1.1e" }, + [pcxu] = { "PA8000 (PCX-U)", "2.0" }, + [pcxu_] = { "PA8200 (PCX-U+)", "2.0" }, + [pcxw] = { "PA8500 (PCX-W)", "2.0" }, + [pcxw_] = { "PA8600 (PCX-W+)", "2.0" }, + [pcxw2] = { "PA8700 (PCX-W2)", "2.0" }, + [mako] = { "PA8800 (Mako)", "2.0" } }; const char * __init diff --git a/arch/parisc/kernel/ioctl32.c b/arch/parisc/kernel/ioctl32.c index 53ef897ec405..1d3824b670d1 100644 --- a/arch/parisc/kernel/ioctl32.c +++ b/arch/parisc/kernel/ioctl32.c @@ -563,7 +563,7 @@ static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) #endif -#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, 0 }, +#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, NULL }, #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd, sys_ioctl) #define IOCTL_TABLE_START struct ioctl_trans ioctl_start[] = { diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index f8bacd79a631..ff1684ddc984 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -157,16 +157,16 @@ static struct rdr_tbl_ent perf_rdr_tbl_U[] = { * this array. */ static uint64_t perf_bitmasks[] = { - 0x0000000000000000, /* first dbl word must be zero */ - 0xfdffe00000000000, /* RDR0 bitmask */ - 0x003f000000000000, /* RDR1 bitmask */ - 0x00ffffffffffffff, /* RDR20-RDR21 bitmask (152 bits) */ - 0xffffffffffffffff, - 0xfffffffc00000000, - 0xffffffffffffffff, /* RDR22-RDR23 bitmask (233 bits) */ - 0xffffffffffffffff, - 0xfffffffffffffffc, - 0xff00000000000000 + 0x0000000000000000ul, /* first dbl word must be zero */ + 0xfdffe00000000000ul, /* RDR0 bitmask */ + 0x003f000000000000ul, /* RDR1 bitmask */ + 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (152 bits) */ + 0xfffffffffffffffful, + 0xfffffffc00000000ul, + 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (233 bits) */ + 0xfffffffffffffffful, + 0xfffffffffffffffcul, + 0xff00000000000000ul }; /* @@ -174,16 +174,16 @@ static uint64_t perf_bitmasks[] = { * somethings have changed slightly. */ static uint64_t perf_bitmasks_piranha[] = { - 0x0000000000000000, /* first dbl word must be zero */ - 0xfdffe00000000000, /* RDR0 bitmask */ - 0x003f000000000000, /* RDR1 bitmask */ - 0x00ffffffffffffff, /* RDR20-RDR21 bitmask (158 bits) */ - 0xffffffffffffffff, - 0xfffffffc00000000, - 0xffffffffffffffff, /* RDR22-RDR23 bitmask (210 bits) */ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xfffc000000000000 + 0x0000000000000000ul, /* first dbl word must be zero */ + 0xfdffe00000000000ul, /* RDR0 bitmask */ + 0x003f000000000000ul, /* RDR1 bitmask */ + 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (158 bits) */ + 0xfffffffffffffffful, + 0xfffffffc00000000ul, + 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (210 bits) */ + 0xfffffffffffffffful, + 0xfffffffffffffffful, + 0xfffc000000000000ul }; static uint64_t *bitmask_array; /* array of bitmasks to use */ @@ -194,8 +194,8 @@ static uint64_t *bitmask_array; /* array of bitmasks to use */ static int perf_config(uint32_t *image_ptr); static int perf_release(struct inode *inode, struct file *file); static int perf_open(struct inode *inode, struct file *file); -static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos); -static ssize_t perf_write(struct file *file, const char *buf, size_t count, +static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos); +static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos); static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -287,7 +287,7 @@ static int perf_release(struct inode *inode, struct file *file) /* * Read does nothing for this driver */ -static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos) +static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) { return 0; } @@ -299,7 +299,7 @@ static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos) * called on the processor that the download should happen * on. */ -static ssize_t perf_write(struct file *file, const char *buf, size_t count, +static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int err; @@ -460,7 +460,7 @@ static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } /* copy out the Counters */ - if (copy_to_user((void *)arg, raddr, + if (copy_to_user((void __user *)arg, raddr, sizeof (raddr)) != 0) { return -EFAULT; } @@ -607,7 +607,7 @@ static int perf_stop_counters(uint32_t *raddr) * all of dword 22 and 58 bits (plus 6 don't care bits) of * dword 23. */ - userbuf[21] &= 0xfffffffffffffc00; /* 0 to last 10 bits */ + userbuf[21] &= 0xfffffffffffffc00ul; /* 0 to last 10 bits */ userbuf[22] = 0; userbuf[23] = 0; @@ -802,8 +802,8 @@ static int perf_write_image(uint64_t *memaddr) proc_hpa = cpu_device->hpa; /* Merge intrigue bits into Runway STATUS 0 */ - tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecffffffffffff; - __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000), proc_hpa + RUNWAY_STATUS); + tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecfffffffffffful; + __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), proc_hpa + RUNWAY_STATUS); /* Write RUNWAY DEBUG registers */ for (i = 0; i < 8; i++) { diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 320fca55fa1a..d2d247a78a75 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -251,7 +251,7 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { - int *user_tid = (int *)regs->gr[26]; + int __user *user_tid = (int __user *)regs->gr[26]; /* usp must be word aligned. This also prevents users from * passing in the value 1 (which is the signal for a special @@ -357,12 +357,12 @@ asmlinkage int sys_execve(struct pt_regs *regs) int error; char *filename; - filename = getname((char *) regs->gr[26]); + filename = getname((const char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char **) regs->gr[25], - (char **) regs->gr[24], regs); + error = do_execve(filename, (char __user **) regs->gr[25], + (char __user **) regs->gr[24], regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index f3267597085b..40fc427b5d54 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -199,7 +199,7 @@ static void __init parisc_proc_mkdir(void) case pcxl2: if (NULL == proc_gsc_root) { - proc_gsc_root = proc_mkdir("bus/gsc", 0); + proc_gsc_root = proc_mkdir("bus/gsc", NULL); } break; case pcxt_: @@ -210,13 +210,13 @@ static void __init parisc_proc_mkdir(void) case pcxw2: if (NULL == proc_runway_root) { - proc_runway_root = proc_mkdir("bus/runway", 0); + proc_runway_root = proc_mkdir("bus/runway", NULL); } break; case mako: if (NULL == proc_mckinley_root) { - proc_mckinley_root = proc_mkdir("bus/mckinley", 0); + proc_mckinley_root = proc_mkdir("bus/mckinley", NULL); } break; default: diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 4a0a8adbc79d..218ce66290dd 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -69,7 +69,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); #endif asmlinkage int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) +sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) { sigset_t saveset, newset; #ifdef __LP64__ @@ -79,7 +79,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - if (copy_from_user(&newset32, (compat_sigset_t *)unewset, sizeof(newset32))) + if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32))) return -EFAULT; sigset_32to64(&newset,&newset32); @@ -125,7 +125,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ static long -restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs) +restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) { long err = 0; @@ -143,14 +143,14 @@ restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs) void sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; struct siginfo si; sigset_t set; unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; #ifdef __LP64__ compat_sigset_t compat_set; - struct compat_rt_sigframe * compat_frame; + struct compat_rt_sigframe __user * compat_frame; if(personality(current->personality) == PER_LINUX32) sigframe_size = PARISC_RT_SIGFRAME_SIZE32; @@ -158,12 +158,12 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) /* Unwind the user stack to get the rt_sigframe structure. */ - frame = (struct rt_sigframe *) + frame = (struct rt_sigframe __user *) (usp - sigframe_size); DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); #ifdef __LP64__ - compat_frame = (struct compat_rt_sigframe *)frame; + compat_frame = (struct compat_rt_sigframe __user *)frame; if(personality(current->personality) == PER_LINUX32){ DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); @@ -238,7 +238,7 @@ give_sigsegv: * Set up a signal frame. */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) { /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we @@ -251,11 +251,11 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) sp = current->sas_ss_sp; /* Stacks grow up! */ DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); - return (void *) sp; /* Stacks grow up. Fun. */ + return (void __user *) sp; /* Stacks grow up. Fun. */ } static long -setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall) +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall) { unsigned long flags = 0; @@ -292,14 +292,14 @@ static long setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs, int in_syscall) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; unsigned long rp, usp; unsigned long haddr, sigframe_size; struct siginfo si; int err = 0; #ifdef __LP64__ compat_int_t compat_val; - struct compat_rt_sigframe * compat_frame; + struct compat_rt_sigframe __user * compat_frame; compat_sigset_t compat_set; #endif @@ -313,7 +313,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #ifdef __LP64__ - compat_frame = (struct compat_rt_sigframe *)frame; + compat_frame = (struct compat_rt_sigframe __user *)frame; if(personality(current->personality) == PER_LINUX32) { DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); @@ -396,7 +396,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #endif if (haddr & PA_PLABEL_FDESC) { Elf32_Fdesc fdesc; - Elf32_Fdesc *ufdesc = (Elf32_Fdesc *)A(haddr & ~3); + Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); @@ -409,7 +409,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #ifdef __LP64__ } else { Elf64_Fdesc fdesc; - Elf64_Fdesc *ufdesc = (Elf64_Fdesc *)A(haddr & ~3); + Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 1c1668b6f02f..c4a06bc446cf 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -65,7 +65,7 @@ sigset_64to32(compat_sigset_t *s32, sigset_t *s64) } static int -put_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz) +put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; @@ -76,7 +76,7 @@ put_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz) } static int -get_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz) +get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; int r; @@ -90,7 +90,7 @@ get_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz) return r; } -int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset, +int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, unsigned int sigsetsize) { sigset_t old_set, new_set; @@ -99,8 +99,8 @@ int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset, if (set && get_sigset32(set, &new_set, sigsetsize)) return -EFAULT; - KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? &new_set : NULL, - oset ? &old_set : NULL, sigsetsize); + KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL, + oset ? (sigset_t __user *)&old_set : NULL, sigsetsize); if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize)) return -EFAULT; @@ -109,12 +109,12 @@ int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset, } -int sys32_rt_sigpending(compat_sigset_t *uset, unsigned int sigsetsize) +int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize) { int ret; sigset_t set; - KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize); + KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize); if (!ret && put_sigset32(uset, &set, sigsetsize)) return -EFAULT; @@ -123,7 +123,7 @@ int sys32_rt_sigpending(compat_sigset_t *uset, unsigned int sigsetsize) } long -sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact, +sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction32 new_sa32, old_sa32; @@ -151,7 +151,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *o } int -do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned long sp) +do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp) { compat_stack_t ss32, oss32; stack_t ss, oss; @@ -162,7 +162,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned if (copy_from_user(&ss32, uss32, sizeof ss32)) return -EFAULT; - ss.ss_sp = (void *)(unsigned long)ss32.ss_sp; + ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp; ss.ss_flags = ss32.ss_flags; ss.ss_size = ss32.ss_size; @@ -172,7 +172,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned if (uoss32) ossp = &oss; - KERNEL_SYSCALL(ret, do_sigaltstack, ssp, ossp, sp); + KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp); if (!ret && uoss32) { oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp; @@ -186,7 +186,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned } long -restore_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf, +restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, struct pt_regs *regs) { long err = 0; @@ -265,7 +265,7 @@ restore_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf, * truncate for a 32-bit userspace. */ long -setup_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf, +setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, struct pt_regs *regs, int in_syscall) { compat_int_t flags = 0; diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index 9c29b63d9e4a..4d1569e717cc 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -31,13 +31,13 @@ struct k_sigaction32 { void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); -int do_sigaltstack32 (const compat_stack_t *uss32, - compat_stack_t *uoss32, unsigned long sp); -long restore_sigcontext32(struct compat_sigcontext *sc, - struct compat_regfile *rf, +int do_sigaltstack32 (const compat_stack_t __user *uss32, + compat_stack_t __user *uoss32, unsigned long sp); +long restore_sigcontext32(struct compat_sigcontext __user *sc, + struct compat_regfile __user *rf, struct pt_regs *regs); -long setup_sigcontext32(struct compat_sigcontext *sc, - struct compat_regfile *rf, +long setup_sigcontext32(struct compat_sigcontext __user *sc, + struct compat_regfile __user *rf, struct pt_regs *regs, int in_syscall); #endif diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 96ad250edfa5..7958cd8c8bf8 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -32,7 +32,7 @@ #include #include -int sys_pipe(int *fildes) +int sys_pipe(int __user *fildes) { int fd[2]; int error; @@ -161,7 +161,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, } } -long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag) +long sys_shmat_wrapper(int shmid, char __user *shmaddr, int shmflag) { unsigned long raddr; int r; @@ -174,8 +174,8 @@ long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag) /* Fucking broken ABI */ -#ifdef CONFIG_PARISC64 -asmlinkage long parisc_truncate64(const char * path, +#ifdef CONFIG_64BIT +asmlinkage long parisc_truncate64(const char __user * path, unsigned int high, unsigned int low) { return sys_truncate(path, (long)high << 32 | low); @@ -189,7 +189,7 @@ asmlinkage long parisc_ftruncate64(unsigned int fd, /* stubs for the benefit of the syscall_table since truncate64 and truncate * are identical on LP64 */ -asmlinkage long sys_truncate64(const char * path, unsigned long length) +asmlinkage long sys_truncate64(const char __user * path, unsigned long length) { return sys_truncate(path, length); } @@ -203,7 +203,7 @@ asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg } #else -asmlinkage long parisc_truncate64(const char * path, +asmlinkage long parisc_truncate64(const char __user * path, unsigned int high, unsigned int low) { return sys_truncate64(path, (loff_t)high << 32 | low); @@ -216,13 +216,13 @@ asmlinkage long parisc_ftruncate64(unsigned int fd, } #endif -asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count, +asmlinkage ssize_t parisc_pread64(unsigned int fd, char __user *buf, size_t count, unsigned int high, unsigned int low) { return sys_pread64(fd, buf, count, (loff_t)high << 32 | low); } -asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf, +asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char __user *buf, size_t count, unsigned int high, unsigned int low) { return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low); diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index e4e6bfcaa711..ed58d1a5d825 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -74,7 +74,7 @@ asmlinkage int sys32_execve(struct pt_regs *regs) char *filename; DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26])); - filename = getname((char *) regs->gr[26]); + filename = getname((const char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; @@ -111,13 +111,13 @@ struct __sysctl_args32 { u32 __unused[4]; }; -asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) +asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) { struct __sysctl_args32 tmp; int error; unsigned int oldlen32; size_t oldlen, *oldlenp = NULL; - unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; + unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7; extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen); @@ -159,7 +159,7 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) error = -EFAULT; } } - if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused))) + if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused))) error = -EFAULT; } return error; @@ -168,19 +168,19 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) #endif /* CONFIG_SYSCTL */ asmlinkage long sys32_sched_rr_get_interval(pid_t pid, - struct compat_timespec *interval) + struct compat_timespec __user *interval) { struct timespec t; int ret; - - KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t); + + KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t); if (put_compat_timespec(&t, interval)) return -EFAULT; return ret; } static int -put_compat_timeval(struct compat_timeval *u, struct timeval *t) +put_compat_timeval(struct compat_timeval __user *u, struct timeval *t) { struct compat_timeval t32; t32.tv_sec = t->tv_sec; @@ -188,7 +188,7 @@ put_compat_timeval(struct compat_timeval *u, struct timeval *t) return copy_to_user(u, &t32, sizeof t32); } -static inline long get_ts32(struct timespec *o, struct compat_timeval *i) +static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) { long usec; @@ -201,7 +201,7 @@ static inline long get_ts32(struct timespec *o, struct compat_timeval *i) } asmlinkage int -sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz) +sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { extern void do_gettimeofday(struct timeval *tv); @@ -220,7 +220,7 @@ sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz) } asmlinkage -int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz) +int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { struct timespec kts; struct timezone ktz; @@ -237,7 +237,7 @@ int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz) return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } -int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf) +int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) { int err; @@ -294,24 +294,24 @@ struct old_linux32_dirent { }; struct getdents32_callback { - struct linux32_dirent * current_dir; - struct linux32_dirent * previous; + struct linux32_dirent __user * current_dir; + struct linux32_dirent __user * previous; int count; int error; }; struct readdir32_callback { - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; int count; }; #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) static int filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct linux32_dirent * dirent; + struct linux32_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); @@ -327,17 +327,17 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - dirent = (struct linux32_dirent *)((char *)dirent + reclen); + dirent = ((void __user *)dirent) + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; } asmlinkage long -sys32_getdents (unsigned int fd, void * dirent, unsigned int count) +sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count) { struct file * file; - struct linux32_dirent * lastdirent; + struct linux32_dirent __user * lastdirent; struct getdents32_callback buf; int error; @@ -346,7 +346,7 @@ sys32_getdents (unsigned int fd, void * dirent, unsigned int count) if (!file) goto out; - buf.current_dir = (struct linux32_dirent *) dirent; + buf.current_dir = (struct linux32_dirent __user *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -372,7 +372,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t unsigned int d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; - struct old_linux32_dirent * dirent; + struct old_linux32_dirent __user * dirent; if (buf->count) return -EINVAL; @@ -387,7 +387,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t } asmlinkage long -sys32_readdir (unsigned int fd, void * dirent, unsigned int count) +sys32_readdir (unsigned int fd, void __user * dirent, unsigned int count) { int error; struct file * file; @@ -477,7 +477,7 @@ struct msgbuf32 { }; asmlinkage long sys32_msgsnd(int msqid, - struct msgbuf32 *umsgp32, + struct msgbuf32 __user *umsgp32, size_t msgsz, int msgflg) { struct msgbuf *mb; @@ -494,14 +494,14 @@ asmlinkage long sys32_msgsnd(int msqid, if (err) err = -EFAULT; else - KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg); + KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg); kfree(mb); return err; } asmlinkage long sys32_msgrcv(int msqid, - struct msgbuf32 *umsgp32, + struct msgbuf32 __user *umsgp32, size_t msgsz, long msgtyp, int msgflg) { struct msgbuf *mb; @@ -511,7 +511,7 @@ asmlinkage long sys32_msgrcv(int msqid, if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) return -ENOMEM; - KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg); + KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg); if (err >= 0) { len = err; @@ -528,7 +528,7 @@ asmlinkage long sys32_msgrcv(int msqid, return err; } -asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count) +asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -538,7 +538,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 c return -EFAULT; set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count); set_fs(old_fs); if (offset && put_user(of, offset)) @@ -547,9 +547,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 c return ret; } -typedef long __kernel_loff_t32; /* move this to asm/posix_types.h? */ - -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count) +asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -559,7 +557,7 @@ asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset return -EFAULT; set_fs(KERNEL_DS); - ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count); + ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count); set_fs(old_fs); if (offset && put_user(lof, offset)) @@ -598,7 +596,7 @@ struct timex32 { int :32; int :32; int :32; int :32; }; -asmlinkage long sys32_adjtimex(struct timex32 *txc_p32) +asmlinkage long sys32_adjtimex(struct timex32 __user *txc_p32) { struct timex txc; struct timex32 t32; @@ -647,7 +645,7 @@ struct sysinfo32 { * damage, I decided to just duplicate the code from sys_sysinfo here. */ -asmlinkage int sys32_sysinfo(struct sysinfo32 *info) +asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info) { struct sysinfo val; int err; @@ -714,7 +712,7 @@ asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg) return sys_semctl (semid, semnum, cmd, arg); } -long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf, +long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf, size_t len) { return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low, diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 69a253fe2e8d..32b56595cf51 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -242,7 +242,7 @@ void handle_gdb_break(struct pt_regs *regs, int wot) struct siginfo si; si.si_code = wot; - si.si_addr = (void *) (regs->iaoq[0] & ~3); + si.si_addr = (void __user *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; si.si_errno = 0; force_sig_info(SIGTRAP, &si, current); @@ -263,7 +263,7 @@ void handle_break(unsigned iir, struct pt_regs *regs) show_regs(regs); #endif si.si_code = TRAP_BRKPT; - si.si_addr = (void *) (regs->iaoq[0] & ~3); + si.si_addr = (void __user *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; force_sig_info(SIGTRAP, &si, current); break; @@ -281,7 +281,7 @@ void handle_break(unsigned iir, struct pt_regs *regs) #endif si.si_signo = SIGTRAP; si.si_code = TRAP_BRKPT; - si.si_addr = (void *) (regs->iaoq[0] & ~3); + si.si_addr = (void __user *) (regs->iaoq[0] & ~3); force_sig_info(SIGTRAP, &si, current); return; } @@ -569,7 +569,7 @@ void handle_interruption(int code, struct pt_regs *regs) give_sigill: si.si_signo = SIGILL; si.si_errno = 0; - si.si_addr = (void *) regs->iaoq[0]; + si.si_addr = (void __user *) regs->iaoq[0]; force_sig_info(SIGILL, &si, current); return; @@ -577,7 +577,7 @@ void handle_interruption(int code, struct pt_regs *regs) /* Overflow Trap, let the userland signal handler do the cleanup */ si.si_signo = SIGFPE; si.si_code = FPE_INTOVF; - si.si_addr = (void *) regs->iaoq[0]; + si.si_addr = (void __user *) regs->iaoq[0]; force_sig_info(SIGFPE, &si, current); return; @@ -699,9 +699,9 @@ void handle_interruption(int code, struct pt_regs *regs) si.si_signo = SIGSEGV; si.si_errno = 0; if (code == 7) - si.si_addr = (void *) regs->iaoq[0]; + si.si_addr = (void __user *) regs->iaoq[0]; else - si.si_addr = (void *) regs->ior; + si.si_addr = (void __user *) regs->ior; force_sig_info(SIGSEGV, &si, current); return; @@ -721,7 +721,7 @@ void handle_interruption(int code, struct pt_regs *regs) si.si_signo = SIGBUS; si.si_code = BUS_OBJERR; si.si_errno = 0; - si.si_addr = (void *) regs->ior; + si.si_addr = (void __user *) regs->ior; force_sig_info(SIGBUS, &si, current); return; } @@ -745,7 +745,7 @@ void handle_interruption(int code, struct pt_regs *regs) si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SEGV_MAPERR; - si.si_addr = (void *) regs->ior; + si.si_addr = (void __user *) regs->ior; force_sig_info(SIGSEGV, &si, current); return; } diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 3eda1dadc379..62eea35bcd69 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -744,7 +744,7 @@ void handle_unaligned(struct pt_regs *regs) si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SEGV_MAPERR; - si.si_addr = (void *)regs->ior; + si.si_addr = (void __user *)regs->ior; force_sig_info(SIGSEGV, &si, current); } else @@ -754,7 +754,7 @@ force_sigbus: si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRALN; - si.si_addr = (void *)regs->ior; + si.si_addr = (void __user *)regs->ior; force_sig_info(SIGBUS, &si, current); } diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c index 9866c93f1e6f..8a1e08068e7d 100644 --- a/arch/parisc/lib/checksum.c +++ b/arch/parisc/lib/checksum.c @@ -131,9 +131,9 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck); * Copy from userspace and compute checksum. If we catch an exception * then zero the rest of the buffer. */ -unsigned int csum_partial_copy_from_user (const unsigned char *src, unsigned char *dst, - int len, unsigned int sum, - int *err_ptr) +unsigned int csum_partial_copy_from_user(const unsigned char __user *src, + unsigned char *dst, int len, + unsigned int sum, int *err_ptr) { int missing; diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c index e202c240f06f..70721b25f322 100644 --- a/arch/parisc/math-emu/driver.c +++ b/arch/parisc/math-emu/driver.c @@ -120,7 +120,7 @@ handle_fpe(struct pt_regs *regs) si.si_signo = signalcode >> 24; si.si_errno = 0; si.si_code = signalcode & 0xffffff; - si.si_addr = (void *) regs->iaoq[0]; + si.si_addr = (void __user *) regs->iaoq[0]; force_sig_info(si.si_signo, &si, current); return -1; } diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index fd1c77280b35..eaa701479f5f 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -225,7 +225,7 @@ bad_area: si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SEGV_MAPERR; - si.si_addr = (void *) address; + si.si_addr = (void __user *) address; force_sig_info(SIGSEGV, &si, current); return; } diff --git a/include/asm-parisc/checksum.h b/include/asm-parisc/checksum.h index f8bfc4c72236..229cb56fdb7a 100644 --- a/include/asm-parisc/checksum.h +++ b/include/asm-parisc/checksum.h @@ -30,8 +30,8 @@ extern unsigned int csum_partial_copy_nocheck(const unsigned char *, unsigned ch * this is a new version of the above that records errors it finds in *errp, * but continues and zeros the rest of the buffer. */ -extern unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, - int len, unsigned int sum, int *errp); +extern unsigned int csum_partial_copy_from_user(const unsigned char __user *src, + unsigned char *dst, int len, unsigned int sum, int *errp); /* * Optimized for IP headers, which always checksum on 4 octet boundaries. diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index 3edb5db3eace..ca0eac647a05 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h @@ -131,15 +131,15 @@ typedef u32 compat_sigset_word; */ typedef u32 compat_uptr_t; -static inline void *compat_ptr(compat_uptr_t uptr) +static inline void __user *compat_ptr(compat_uptr_t uptr) { - return (void *)(unsigned long)uptr; + return (void __user *)(unsigned long)uptr; } -static __inline__ void *compat_alloc_user_space(long len) +static __inline__ void __user *compat_alloc_user_space(long len) { struct pt_regs *regs = ¤t->thread.regs; - return (void *)regs->gr[30]; + return (void __user *)regs->gr[30]; } #endif /* _ASM_PARISC_COMPAT_H */ diff --git a/include/asm-parisc/signal.h b/include/asm-parisc/signal.h index cd4beefef333..358f577c8eb8 100644 --- a/include/asm-parisc/signal.h +++ b/include/asm-parisc/signal.h @@ -123,13 +123,14 @@ struct siginfo; * compiler doesn't support code which changes or tests the address of * the function in the little struct. This is really ugly -PB */ -typedef __kernel_caddr_t __sighandler_t; +typedef char __user *__sighandler_t; #else -typedef void (*__sighandler_t)(int); +typedef void __signalfn_t(int); +typedef __signalfn_t __user *__sighandler_t; #endif typedef struct sigaltstack { - void *ss_sp; + void __user *ss_sp; int ss_flags; size_t ss_size; } stack_t; -- cgit v1.2.3 From 16b81eccbfaa784f801af8e67cea7e924b572f2f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Mar 2005 16:12:57 -0800 Subject: [PATCH] Improve PA-RISC make configcheck Fix "make configcheck | fgrep 'not needed' | fgrep parisc" Signed-off-by: Grant Grundler Signed-off-by: Matthew Wilcox Signed-off-by: Linus Torvalds --- arch/parisc/kernel/binfmt_elf32.c | 1 - arch/parisc/kernel/perf.c | 1 - arch/parisc/kernel/signal32.c | 1 - arch/parisc/math-emu/driver.c | 1 - drivers/parisc/eisa_eeprom.c | 1 - drivers/parisc/hppb.c | 1 - include/asm-parisc/ide.h | 2 -- include/asm-parisc/numnodes.h | 2 -- include/asm-parisc/serial.h | 2 -- 9 files changed, 12 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index 6fd07e90aad7..d1833f164bbe 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -37,7 +37,6 @@ typedef unsigned int elf_greg_t; #include #include #include -#include #include #include /* struct compat_timeval */ diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index ff1684ddc984..b3ad0a505b87 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -42,7 +42,6 @@ * on every box. */ -#include #include #include #include diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index c4a06bc446cf..0792e20efef3 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -20,7 +20,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c index 70721b25f322..09ef4136c693 100644 --- a/arch/parisc/math-emu/driver.c +++ b/arch/parisc/math-emu/driver.c @@ -27,7 +27,6 @@ * Copyright (C) 2001 Hewlett-Packard */ -#include #include #include "float.h" #include "math-emu.h" diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c index d16724dbe890..ea9ebc7f2c24 100644 --- a/drivers/parisc/eisa_eeprom.c +++ b/drivers/parisc/eisa_eeprom.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index 8bda8bb50815..e869c6020370 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -16,7 +16,6 @@ ** */ -#include #include #include #include diff --git a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h index 15a9374c1c0f..a463c8642cab 100644 --- a/include/asm-parisc/ide.h +++ b/include/asm-parisc/ide.h @@ -13,8 +13,6 @@ #ifdef __KERNEL__ -#include - #ifndef MAX_HWIFS #define MAX_HWIFS 2 #endif diff --git a/include/asm-parisc/numnodes.h b/include/asm-parisc/numnodes.h index dcdd933eb60b..6c67651efd1c 100644 --- a/include/asm-parisc/numnodes.h +++ b/include/asm-parisc/numnodes.h @@ -1,8 +1,6 @@ #ifndef _ASM_MAX_NUMNODES_H #define _ASM_MAX_NUMNODES_H -#include - /* Max 8 Nodes */ #define NODES_SHIFT 3 diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h index 230644f9e28e..239c5dcab7e6 100644 --- a/include/asm-parisc/serial.h +++ b/include/asm-parisc/serial.h @@ -2,8 +2,6 @@ * include/asm-parisc/serial.h */ -#include - /* * This assumes you have a 7.272727 MHz clock for your UART. * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock -- cgit v1.2.3 From 6365711de73b0e67cf2c8e496300dbfe491d2a8c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Mar 2005 16:13:13 -0800 Subject: [PATCH] PA-RISC irq handling improvements - Move the bits_wide parameter from txn_alloc_data to txn_alloc_irq. It's too late by the time it hits txn_alloc_data(), we can only panic. In txn_alloc_irq, we can fail the allocation and continue. - Also fix a bug where we'd only allow up to half the interrupts to be allocated. Not a problem for iosapic machines, but might have sucked on a really big GSC-based machine. - Add missing irq_enter() / irq_exit() - Allow interrupt processing to be interrupted by the timer tick so we actually account hard interrupts. Also speed up the handling of CPU interrupts by not masking with cpu_eiem again. - Remove sufficiently obsolete DEBUG_IRQ code - Remove limit on times around the loop. If we exit the loop while interrupts are still pending, we'll only be re-interrupted as soon as we exit the function. - Remove unnecessary includes Signed-off-by: Matthew Wilcox Signed-off-by: Linus Torvalds --- arch/parisc/kernel/irq.c | 104 ++++++++++++++++------------------------------- drivers/parisc/gsc.c | 6 +-- include/asm-parisc/irq.h | 8 ++-- 3 files changed, 44 insertions(+), 74 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 6388172ec235..04febd66b0ea 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -5,6 +5,7 @@ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org) * Copyright (C) 1999-2000 Grant Grundler + * Copyright (c) 2005 Matthew Wilcox * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,38 +23,19 @@ */ #include #include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include +#include -#include -#include - -#undef DEBUG_IRQ #undef PARISC_IRQ_CR16_COUNTS extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); -#ifdef DEBUG_IRQ -#define DBG_IRQ(irq, x) if ((irq) != TIMER_IRQ) printk x -#else /* DEBUG_IRQ */ -#define DBG_IRQ(irq, x) do { } while (0) -#endif /* DEBUG_IRQ */ - #define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq)) /* Bits in EIEM correlate with cpu_irq_action[]. @@ -200,7 +182,25 @@ int txn_claim_irq(int irq) return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq; } -int txn_alloc_irq(void) +/* + * The bits_wide parameter accommodates the limitations of the HW/SW which + * use these bits: + * Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register) + * V-class (EPIC): 6 bits + * N/L/A-class (iosapic): 8 bits + * PCI 2.2 MSI: 16 bits + * Some PCI devices: 32 bits (Symbios SCSI/ATM/HyperFabric) + * + * On the service provider side: + * o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register) + * o PA 2.0 wide mode 6-bits (per processor) + * o IA64 8-bits (0-256 total) + * + * So a Legacy PA I/O device on a PA 2.0 box can't use all the bits supported + * by the processor...and the N/L-class I/O subsystem supports more bits than + * PA2.0 has. The first case is the problem. + */ +int txn_alloc_irq(unsigned int bits_wide) { int irq; @@ -208,6 +208,8 @@ int txn_alloc_irq(void) for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) { if (cpu_claim_irq(irq, NULL, NULL) < 0) continue; + if ((irq - CPU_IRQ_BASE) >= (1 << bits_wide)) + continue; return irq; } @@ -215,7 +217,7 @@ int txn_alloc_irq(void) return -1; } -unsigned long txn_alloc_addr(int virt_irq) +unsigned long txn_alloc_addr(unsigned int virt_irq) { static int next_cpu = -1; @@ -233,36 +235,8 @@ unsigned long txn_alloc_addr(int virt_irq) } -/* -** The alloc process needs to accept a parameter to accommodate limitations -** of the HW/SW which use these bits: -** Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register) -** V-class (EPIC): 6 bits -** N/L-class/A500: 8 bits (iosapic) -** PCI 2.2 MSI: 16 bits (I think) -** Existing PCI devices: 32-bits (all Symbios SCSI/ATM/HyperFabric) -** -** On the service provider side: -** o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register) -** o PA 2.0 wide mode 6-bits (per processor) -** o IA64 8-bits (0-256 total) -** -** So a Legacy PA I/O device on a PA 2.0 box can't use all -** the bits supported by the processor...and the N/L-class -** I/O subsystem supports more bits than PA2.0 has. The first -** case is the problem. -*/ -unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide) +unsigned int txn_alloc_data(unsigned int virt_irq) { - /* XXX FIXME : bits_wide indicates how wide the transaction - ** data is allowed to be...we may need a different virt_irq - ** if this one won't work. Another reason to index virtual - ** irq's into a table which can manage CPU/IRQ bit separately. - */ - if ((virt_irq - CPU_IRQ_BASE) > (1 << (bits_wide - 1))) { - panic("Sorry -- didn't allocate valid IRQ for this device\n"); - } - return virt_irq - CPU_IRQ_BASE; } @@ -270,42 +244,35 @@ unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide) void do_cpu_irq_mask(struct pt_regs *regs) { unsigned long eirr_val; - unsigned int i=3; /* limit time in interrupt context */ + + irq_enter(); /* - * PSW_I or EIEM bits cannot be enabled until after the - * interrupts are processed. - * timer_interrupt() assumes it won't get interrupted when it - * holds the xtime_lock...an unmasked interrupt source could - * interrupt and deadlock by trying to grab xtime_lock too. - * Keeping PSW_I and EIEM disabled avoids this. + * Only allow interrupt processing to be interrupted by the + * timer tick */ - set_eiem(0UL); /* disable all extr interrupt for now */ + set_eiem(EIEM_MASK(TIMER_IRQ)); /* 1) only process IRQs that are enabled/unmasked (cpu_eiem) * 2) We loop here on EIRR contents in order to avoid * nested interrupts or having to take another interrupt * when we could have just handled it right away. - * 3) Limit the number of times we loop to make sure other - * processing can occur. */ for (;;) { unsigned long bit = (1UL << (BITS_PER_LONG - 1)); unsigned int irq; eirr_val = mfctl(23) & cpu_eiem; - if (!eirr_val || !i--) + if (!eirr_val) break; - mtctl(eirr_val, 23); /* reset bits we are going to process */ + if (eirr_val & EIEM_MASK(TIMER_IRQ)) + set_eiem(0); -#ifdef DEBUG_IRQ - if (eirr_val != (1UL << MAX_CPU_IRQ)) - printk(KERN_DEBUG "do_cpu_irq_mask 0x%x & 0x%x\n", eirr_val, cpu_eiem); -#endif + mtctl(eirr_val, 23); /* reset bits we are going to process */ /* Work our way from MSb to LSb...same order we alloc EIRs */ for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) { - if (!(bit & eirr_val & cpu_eiem)) + if (!(bit & eirr_val)) continue; /* clear bit in mask - can exit loop sooner */ @@ -315,6 +282,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) } } set_eiem(cpu_eiem); + irq_exit(); } diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index 17960846935e..3c3dbc59051a 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -38,14 +38,14 @@ int gsc_alloc_irq(struct gsc_irq *i) { - int irq = txn_alloc_irq(); + int irq = txn_alloc_irq(GSC_EIM_WIDTH); if (irq < 0) { printk("cannot get irq\n"); return irq; } i->txn_addr = txn_alloc_addr(irq); - i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->txn_data = txn_alloc_data(irq); i->irq = irq; return irq; @@ -64,7 +64,7 @@ int gsc_claim_irq(struct gsc_irq *i, int irq) } i->txn_addr = txn_alloc_addr(irq); - i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->txn_data = txn_alloc_data(irq); i->irq = irq; return irq; diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h index 4e5fad213c39..75654ba93353 100644 --- a/include/asm-parisc/irq.h +++ b/include/asm-parisc/irq.h @@ -40,10 +40,12 @@ struct hw_interrupt_type; void no_ack_irq(unsigned int irq); void no_end_irq(unsigned int irq); -extern int txn_alloc_irq(void); +extern int txn_alloc_irq(unsigned int nbits); extern int txn_claim_irq(int); -extern unsigned int txn_alloc_data(int, unsigned int); -extern unsigned long txn_alloc_addr(int); +extern unsigned int txn_alloc_data(unsigned int); +extern unsigned long txn_alloc_addr(unsigned int); + +extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); -- cgit v1.2.3 From d9795da7533d783a7bd2b9973ef864f0aa6cc7bd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 8 Mar 2005 16:30:33 -0800 Subject: [PATCH] barrier rework updates As promised to Andrew, here are the latest bits that fixup the block io barrier handling. - Add io scheduler ->deactivate hook to tell the io scheduler is a request is suspended from the block layer. cfq and as needs this hook. - Locking updates - Make sure a driver doesn't reuse the flush rq before a previous one has completed - Typo in the scsi_io_completion() function, the bit shift was wrong - sd needs proper timeout on the flush - remove silly debug leftover in ide-disk wrt "hdc" Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- drivers/block/as-iosched.c | 30 ++++++++++++++++-------------- drivers/block/cfq-iosched.c | 14 ++++++++++---- drivers/block/elevator.c | 28 +++++++++++++++++++++++++++- drivers/block/ll_rw_blk.c | 21 ++++++++++----------- drivers/ide/ide-disk.c | 20 +++++++------------- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/sd.c | 18 +++++++++++++++--- include/linux/blkdev.h | 2 ++ include/linux/elevator.h | 3 +++ 9 files changed, 91 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index fb625b49b831..17f02aa95271 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -1463,34 +1463,35 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->state = AS_RQ_QUEUED; } -/* - * requeue the request. The request has not been completed, nor is it a - * new request, so don't touch accounting. - */ -static void as_requeue_request(request_queue_t *q, struct request *rq) +static void as_deactivate_request(request_queue_t *q, struct request *rq) { struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); if (arq) { - if (arq->state != AS_RQ_REMOVED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); + if (arq->state == AS_RQ_REMOVED) { + arq->state = AS_RQ_DISPATCHED; + if (arq->io_context && arq->io_context->aic) + atomic_inc(&arq->io_context->aic->nr_dispatched); } - - arq->state = AS_RQ_DISPATCHED; - if (arq->io_context && arq->io_context->aic) - atomic_inc(&arq->io_context->aic->nr_dispatched); } else WARN_ON(blk_fs_request(rq) && (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) ); - list_add(&rq->queuelist, ad->dispatch); - /* Stop anticipating - let this request get through */ as_antic_stop(ad); } +/* + * requeue the request. The request has not been completed, nor is it a + * new request, so don't touch accounting. + */ +static void as_requeue_request(request_queue_t *q, struct request *rq) +{ + as_deactivate_request(q, rq); + list_add(&rq->queuelist, &q->queue_head); +} + /* * Account a request that is inserted directly onto the dispatch queue. * arq->io_context->aic->nr_dispatched should not need to be incremented @@ -2080,6 +2081,7 @@ static struct elevator_type iosched_as = { .elevator_add_req_fn = as_insert_request, .elevator_remove_req_fn = as_remove_request, .elevator_requeue_req_fn = as_requeue_request, + .elevator_deactivate_req_fn = as_deactivate_request, .elevator_queue_empty_fn = as_queue_empty, .elevator_completed_req_fn = as_completed_request, .elevator_former_req_fn = as_former_request, diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 4234508565d6..d9aaa42500d0 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -607,10 +607,7 @@ out: return NULL; } -/* - * make sure the service time gets corrected on reissue of this request - */ -static void cfq_requeue_request(request_queue_t *q, struct request *rq) +static void cfq_deactivate_request(request_queue_t *q, struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); @@ -627,6 +624,14 @@ static void cfq_requeue_request(request_queue_t *q, struct request *rq) cfqq->cfqd->rq_in_driver--; } } +} + +/* + * make sure the service time gets corrected on reissue of this request + */ +static void cfq_requeue_request(request_queue_t *q, struct request *rq) +{ + cfq_deactivate_request(q, rq); list_add(&rq->queuelist, &q->queue_head); } @@ -1804,6 +1809,7 @@ static struct elevator_type iosched_cfq = { .elevator_add_req_fn = cfq_insert_request, .elevator_remove_req_fn = cfq_remove_request, .elevator_requeue_req_fn = cfq_requeue_request, + .elevator_deactivate_req_fn = cfq_deactivate_request, .elevator_queue_empty_fn = cfq_queue_empty, .elevator_completed_req_fn = cfq_completed_request, .elevator_former_req_fn = cfq_former_request, diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 241fdbcb29bc..85c72dd3dfee 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -255,8 +255,16 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, e->ops->elevator_merge_req_fn(q, rq, next); } -void elv_requeue_request(request_queue_t *q, struct request *rq) +/* + * For careful internal use by the block layer. Essentially the same as + * a requeue in that it tells the io scheduler that this request is not + * active in the driver or hardware anymore, but we don't want the request + * added back to the scheduler. Function is not exported. + */ +void elv_deactivate_request(request_queue_t *q, struct request *rq) { + elevator_t *e = q->elevator; + /* * it already went through dequeue, we need to decrement the * in_flight count again @@ -264,6 +272,24 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) if (blk_account_rq(rq)) q->in_flight--; + rq->flags &= ~REQ_STARTED; + + if (e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); +} + +void elv_requeue_request(request_queue_t *q, struct request *rq) +{ + elv_deactivate_request(q, rq); + + /* + * if this is the flush, requeue the original instead and drop the flush + */ + if (rq->flags & REQ_BAR_FLUSH) { + clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); + rq = rq->end_io_data; + } + /* * if iosched has an explicit requeue hook, then use that. otherwise * just put the request at the front of the queue diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 28977a7bad16..0135ec79dc83 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -356,6 +356,7 @@ static void blk_pre_flush_end_io(struct request *flush_rq) else { q->end_flush_fn(q, flush_rq); clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); + q->request_fn(q); } } @@ -366,15 +367,9 @@ static void blk_post_flush_end_io(struct request *flush_rq) rq->flags |= REQ_BAR_POSTFLUSH; - /* - * called from end_that_request_last(), so we know that the queue - * lock is held - */ - spin_unlock(q->queue_lock); q->end_flush_fn(q, flush_rq); - spin_lock(q->queue_lock); - clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); + q->request_fn(q); } struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) @@ -383,9 +378,12 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) BUG_ON(!blk_barrier_rq(rq)); + if (test_and_set_bit(QUEUE_FLAG_FLUSH, &q->queue_flags)) + return NULL; + rq_init(q, flush_rq); flush_rq->elevator_private = NULL; - flush_rq->flags = 0; + flush_rq->flags = REQ_BAR_FLUSH; flush_rq->rq_disk = rq->rq_disk; flush_rq->rl = NULL; @@ -395,11 +393,10 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) */ if (!q->prepare_flush_fn(q, flush_rq)) { rq->flags |= REQ_BAR_PREFLUSH | REQ_BAR_POSTFLUSH; + clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); return rq; } - set_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); - /* * some drivers dequeue requests right away, some only after io * completion. make sure the request is dequeued. @@ -407,6 +404,8 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) if (!list_empty(&rq->queuelist)) blkdev_dequeue_request(rq); + elv_deactivate_request(q, rq); + flush_rq->end_io_data = rq; flush_rq->end_io = blk_pre_flush_end_io; @@ -422,7 +421,7 @@ static void blk_start_post_flush(request_queue_t *q, struct request *rq) rq_init(q, flush_rq); flush_rq->elevator_private = NULL; - flush_rq->flags = 0; + flush_rq->flags = REQ_BAR_FLUSH; flush_rq->rq_disk = rq->rq_disk; flush_rq->rl = NULL; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 36b90f85968c..c256feebd1bd 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -712,12 +712,13 @@ static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq) blk_queue_issue_flush_fn(drive->queue, NULL); good_sectors = 0; } else if (flush_rq->errors) { - sector = ide_get_error_location(drive, flush_rq->buffer); - if ((sector >= rq->hard_sector) && - (sector < rq->hard_sector + rq->hard_nr_sectors)) - good_sectors = sector - rq->hard_sector; - else - good_sectors = 0; + good_sectors = 0; + if (blk_barrier_preflush(rq)) { + sector = ide_get_error_location(drive,flush_rq->buffer); + if ((sector >= rq->hard_sector) && + (sector < rq->hard_sector + rq->hard_nr_sectors)) + good_sectors = sector - rq->hard_sector; + } } if (flush_rq->errors) @@ -729,14 +730,10 @@ static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq) bad_sectors = rq->hard_nr_sectors - good_sectors; - spin_lock(&ide_lock); - if (good_sectors) __ide_end_request(drive, rq, 1, good_sectors); if (bad_sectors) __ide_end_request(drive, rq, 0, bad_sectors); - - spin_unlock(&ide_lock); } static int idedisk_prepare_flush(request_queue_t *q, struct request *rq) @@ -1150,9 +1147,6 @@ static void idedisk_setup (ide_drive_t *drive) barrier = 0; } - if (!strncmp(drive->name, "hdc", 3)) - barrier = 1; - printk(KERN_INFO "%s: cache flushes %ssupported\n", drive->name, barrier ? "" : "not "); if (barrier) { diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e8405375877f..da63045c165d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -697,7 +697,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, int sense_valid = 0; int sense_deferred = 0; - if (blk_complete_barrier_rq(q, req, good_bytes << 9)) + if (blk_complete_barrier_rq(q, req, good_bytes >> 9)) return; /* diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fe8a079b00fb..0fb36703292f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -745,10 +745,21 @@ static void sd_end_flush(request_queue_t *q, struct request *flush_rq) struct scsi_cmnd *cmd = rq->special; unsigned int bytes = rq->hard_nr_sectors << 9; - if (!flush_rq->errors) + if (!flush_rq->errors) { + spin_unlock(q->queue_lock); scsi_io_completion(cmd, bytes, 0); - else + spin_lock(q->queue_lock); + } else if (blk_barrier_postflush(rq)) { + spin_unlock(q->queue_lock); scsi_io_completion(cmd, 0, bytes); + spin_lock(q->queue_lock); + } else { + /* + * force journal abort of barriers + */ + end_that_request_first(rq, -EOPNOTSUPP, rq->hard_nr_sectors); + end_that_request_last(rq); + } } static int sd_prepare_flush(request_queue_t *q, struct request *rq) @@ -758,7 +769,8 @@ static int sd_prepare_flush(request_queue_t *q, struct request *rq) if (sdkp->WCE) { memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->flags = REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; return 1; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 83eef4fde873..266b44fcfaa0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -219,6 +219,7 @@ enum rq_flag_bits { __REQ_PM_SHUTDOWN, /* shutdown request */ __REQ_BAR_PREFLUSH, /* barrier pre-flush done */ __REQ_BAR_POSTFLUSH, /* barrier post-flush */ + __REQ_BAR_FLUSH, /* rq is the flush request */ __REQ_NR_BITS, /* stops here */ }; @@ -246,6 +247,7 @@ enum rq_flag_bits { #define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) #define REQ_BAR_PREFLUSH (1 << __REQ_BAR_PREFLUSH) #define REQ_BAR_POSTFLUSH (1 << __REQ_BAR_POSTFLUSH) +#define REQ_BAR_FLUSH (1 << __REQ_BAR_FLUSH) /* * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 8cf0e3f290bf..ee54f81faad5 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -20,6 +20,7 @@ typedef int (elevator_may_queue_fn) (request_queue_t *, int); typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int); typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); +typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); typedef int (elevator_init_fn) (request_queue_t *, elevator_t *); typedef void (elevator_exit_fn) (elevator_t *); @@ -34,6 +35,7 @@ struct elevator_ops elevator_add_req_fn *elevator_add_req_fn; elevator_remove_req_fn *elevator_remove_req_fn; elevator_requeue_req_fn *elevator_requeue_req_fn; + elevator_deactivate_req_fn *elevator_deactivate_req_fn; elevator_queue_empty_fn *elevator_queue_empty_fn; elevator_completed_req_fn *elevator_completed_req_fn; @@ -87,6 +89,7 @@ extern void elv_merge_requests(request_queue_t *, struct request *, extern void elv_merged_request(request_queue_t *, struct request *); extern void elv_remove_request(request_queue_t *, struct request *); extern void elv_requeue_request(request_queue_t *, struct request *); +extern void elv_deactivate_request(request_queue_t *, struct request *); extern int elv_queue_empty(request_queue_t *); extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(request_queue_t *, struct request *); -- cgit v1.2.3