From eab1f00c61dc8f11994a725efd29ec6e0f1452b7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:07:42 -0800 Subject: [PATCH] USB Storage: unusual_devs.h update On Thu, 19 Feb 2004, Evan Felix wrote: > I plugged a Cyclades AlterPath BIO USb device into my linux 2.6.2 laptop > and it asked me to send you this: > > > hub 1-1.2:1.0: new USB device on port 3, assigned address 6 > hub 1-1.2.3:1.0: USB hub found > hub 1-1.2.3:1.0: 4 ports detected > hub 1-1.2.3:1.0: new USB device on port 1, assigned address 7 > hub 1-1.2.3:1.0: new USB device on port 2, assigned address 8 > Initializing USB Mass Storage driver... > usb-storage: This device (05dc,0001,0001 S 06 P 50) has an unneeded > SubClass entry in unusual_devs.h > Please send a copy of this message to > > scsi0 : SCSI emulation for USB Mass Storage devices > Vendor: Lexar Model: Jumpshot USB CF Rev: 0001 > Type: Direct-Access ANSI SCSI revision: 02 Thank you for sending this. Greg, here's the patch. --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b79810727ba8..a4863d51914c 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -368,7 +368,7 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, "Lexar", "Jumpshot USB CF Reader", - US_SC_SCSI, US_PR_JUMPSHOT, NULL, + US_SC_DEVICE, US_PR_JUMPSHOT, NULL, US_FL_MODE_XLATE ), #endif -- cgit v1.2.3 From c03edb1b941823ca76613560f41744964e172513 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:08:02 -0800 Subject: [PATCH] USB Storage: update unusual_devs.h comments On Tue, 24 Feb 2004, Matthew Dharm wrote: > We should also put a comment into the unusual_devs.h file to make sure > nobody tries to remove the protocol override in the future. How about this? --- drivers/usb/storage/unusual_devs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a4863d51914c..75cb01ba8358 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -619,6 +619,9 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, * are using transport protocol CB. * - They don't like the INQUIRY command. So we must handle this command * of the SCSI layer ourselves. + * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have + * bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB). + * So don't remove the US_PR_CB override! */ UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, "Casio", -- cgit v1.2.3 From b86a731cbcd3c018770b5e415ff730c426bccb64 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:08:22 -0800 Subject: [PATCH] USB: Fix a bug in the UHCI dequeueing code On Mon, 23 Feb 2004, Stephen Hemminger wrote: > Great, the kernel with this patch ran successfully all weekend. Looks like no > more races in the unlink path. Wonderful. Thanks a lot for all your SMP testing, it's been a big help. This patch corrects an error in the dequeueing code for UHCI. Improper locking caused it to hang in the oddball case where an URB was unlinked even before it had been queued. --- drivers/usb/host/uhci-hcd.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 97af20701496..dbac02b619bc 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -1508,12 +1508,9 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) struct urb_priv *urbp = urb->hcpriv; list_del_init(&urbp->urb_list); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - uhci_destroy_urb_priv (uhci, urb); - - return ret; - } - ret = 0; + uhci_destroy_urb_priv(uhci, urb); + } else + ret = 0; out: spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -1649,10 +1646,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp = urb->hcpriv; + struct urb_priv *urbp; spin_lock_irqsave(&uhci->urb_list_lock, flags); - + urbp = urb->hcpriv; + if (!urbp) /* URB was never linked! */ + goto done; list_del_init(&urbp->urb_list); uhci_unlink_generic(uhci, urb); @@ -1665,6 +1664,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); spin_unlock(&uhci->urb_remove_list_lock); +done: spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; } -- cgit v1.2.3 From ff4e68e96c084bd0d973270d79151c549c0a14d1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:08:39 -0800 Subject: [PATCH] USB: Enable interrupts in UHCI after PM resume On Mon, 23 Feb 2004, Chip Salzenberg wrote: > It works ... perfectly! I can now suspend and resume my A30 with > impunity, and the USB keyboard works fine after each resume. > > Thanks much, Alan. > > (Now if I could just get the alsa guys to fix snd-intel8x0...) This patch re-initializes the UHCI Interrupt Enable register following a PM resume. Apparently some systems clear the register during suspend, which causes obvious problems later on. --- drivers/usb/host/uhci-hcd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index dbac02b619bc..94b03918628c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2471,9 +2471,16 @@ static int uhci_resume(struct usb_hcd *hcd) pci_set_master(to_pci_dev(uhci_dev(uhci))); - if (uhci->state == UHCI_SUSPENDED) + if (uhci->state == UHCI_SUSPENDED) { + + /* + * Some systems clear the Interrupt Enable register during + * PM suspend/resume, so reinitialize it. + */ + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | + USBINTR_SP, uhci->io_addr + USBINTR); uhci->resume_detect = 1; - else { + } else { reset_hc(uhci); start_hc(uhci); } -- cgit v1.2.3 From a32564f28b99cc75397c3097b9822a029cfd1a70 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:09:03 -0800 Subject: [PATCH] USB: Return better result codes in UHCI This patch changes the result code returned by the UHCI driver for a certain class of errors. Under a number of circumstances a USB device is obliged to send a response packet within a fairly short turn-around time, typically 1 - 10 microseconds depending on the bus speed. Failure to do so is a protocol error and should be reported as such, not as a timeout, which is really a higher-level concept. I believe the EHCI driver already does this. I trust nobody will object to the update this patch adds to Documentation/usb/error-codes.txt, making this more explicit. In a vaguely related change, the patch corrects the terminology in a few comments. The parts of a control transfer are called "stages", not "phases". --- Documentation/usb/error-codes.txt | 4 +++- drivers/usb/host/uhci-hcd.c | 29 ++++++++++++++--------------- drivers/usb/host/uhci-hcd.h | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt index ef59b543d757..7fb11c33db67 100644 --- a/Documentation/usb/error-codes.txt +++ b/Documentation/usb/error-codes.txt @@ -70,7 +70,9 @@ one or more packets could finish before an error stops further endpoint I/O. (That is, if drivers see this it's a bug.) -EPROTO (*) a) bitstuff error - b) unknown USB error + b) no response packet received within the + prescribed bus turn-around time + c) unknown USB error -EILSEQ (*) CRC mismatch diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 94b03918628c..dd97802d4271 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -781,7 +781,8 @@ static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) /* * Map status to standard result codes * - * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)] + * is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)] + * Note: status does not include the TD_CTRL_NAK bit. * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) @@ -792,22 +793,18 @@ static int uhci_map_status(int status, int dir_out) return -EPROTO; if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ if (dir_out) - return -ETIMEDOUT; + return -EPROTO; else return -EILSEQ; } - if (status & TD_CTRL_NAK) /* NAK */ - return -ETIMEDOUT; if (status & TD_CTRL_BABBLE) /* Babble */ return -EOVERFLOW; if (status & TD_CTRL_DBUFERR) /* Buffer error */ return -ENOSR; if (status & TD_CTRL_STALLED) /* Stalled */ return -EPIPE; - if (status & TD_CTRL_ACTIVE) /* Active */ - return 0; - - return -EINVAL; + WARN_ON(status & TD_CTRL_ACTIVE); /* Active */ + return 0; } /* @@ -832,7 +829,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur status |= TD_CTRL_LS; /* - * Build the TD for the control request + * Build the TD for the control request setup packet */ td = uhci_alloc_td(uhci, urb->dev); if (!td) @@ -990,13 +987,13 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) if (urbp->short_control_packet) { tmp = head->prev; - goto status_phase; + goto status_stage; } tmp = head->next; td = list_entry(tmp, struct uhci_td, list); - /* The first TD is the SETUP phase, check the status, but skip */ + /* The first TD is the SETUP stage, check the status, but skip */ /* the count */ status = uhci_status_bits(td_status(td)); if (status & TD_CTRL_ACTIVE) @@ -1037,10 +1034,10 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) } } -status_phase: +status_stage: td = list_entry(tmp, struct uhci_td, list); - /* Control status phase */ + /* Control status stage */ status = td_status(td); #ifdef I_HAVE_BUGGY_APC_BACKUPS @@ -1053,10 +1050,11 @@ status_phase: return 0; #endif + status = uhci_status_bits(status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - if (uhci_status_bits(status)) + if (status) goto td_error; return 0; @@ -1403,7 +1401,8 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) urb->iso_frame_desc[i].actual_length = actlength; urb->actual_length += actlength; - status = uhci_map_status(uhci_status_bits(td_status(td)), usb_pipeout(urb->pipe)); + status = uhci_map_status(uhci_status_bits(td_status(td)), + usb_pipeout(urb->pipe)); urb->iso_frame_desc[i].status = status; if (status) { urb->error_count++; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 99010c1dbcd0..fb380d7c8e1e 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -141,7 +141,7 @@ struct uhci_qh { TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) #define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT) -#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xFE0000) +#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000) #define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ /* -- cgit v1.2.3 From c09f3a22e7d3cdc95ba48d424ebfaf3b46ad8548 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:09:18 -0800 Subject: [PATCH] USB: Remove name obfuscation in UHCI On Mon, 23 Feb 2004, Stephen Hemminger wrote: > Bulk and interrupt urb's share common irq processing, why does the > code try to obfuscate it? Quite right; this is needless complexity. (But note you left in a couple of lines that should have been deleted.) --- drivers/usb/host/uhci-hcd.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index dd97802d4271..ce72caefd0ce 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -1270,12 +1270,6 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]); } -/* - * Bulk and interrupt use common result - */ -#define uhci_result_bulk uhci_result_common -#define uhci_result_interrupt uhci_result_common - /* * Isochronous transfers */ @@ -1537,11 +1531,9 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) case PIPE_CONTROL: ret = uhci_result_control(uhci, urb); break; - case PIPE_INTERRUPT: - ret = uhci_result_interrupt(uhci, urb); - break; case PIPE_BULK: - ret = uhci_result_bulk(uhci, urb); + case PIPE_INTERRUPT: + ret = uhci_result_common(uhci, urb); break; case PIPE_ISOCHRONOUS: ret = uhci_result_isochronous(uhci, urb); -- cgit v1.2.3 From 56e695be78f47bf882557d1a6258d5bb27a494c0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 25 Feb 2004 22:09:37 -0800 Subject: [PATCH] USB: Use list_splice instead of looping over list elements This patch is from Stephen Hemminger. I modified it slightly to place the new elements at the end of the complete_list instead of at the front. On Tue, 24 Feb 2004, Stephen Hemminger wrote: > Since the remove_list and complete_list now use the same element for > linking, it is possible to use the list_splice inline to avoid > having to loop over all the urb's --- drivers/usb/host/uhci-hcd.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index ce72caefd0ce..876b8364ab88 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -1852,17 +1852,12 @@ static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - spin_lock(&uhci->urb_remove_list_lock); - head = &uhci->urb_remove_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + spin_lock(&uhci->complete_list_lock); - tmp = tmp->next; - uhci_moveto_complete(uhci, urbp); - } + /* Splice the urb_remove_list onto the end of the complete_list */ + list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); + spin_unlock(&uhci->complete_list_lock); spin_unlock(&uhci->urb_remove_list_lock); } -- cgit v1.2.3 From ce6aacf0b54edaef92caa28389d6590eb69bca3b Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Wed, 25 Feb 2004 22:17:58 -0800 Subject: [PATCH] USB Storage: DSC-T1 unusual_devs.h entry Our friends at sony are at it again. The DSC-T1 needs a new entry. Note that it's the same VID & PID as the last entry, but different version. --- drivers/usb/storage/unusual_devs.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 75cb01ba8358..d1bfb3d02d30 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -261,6 +261,14 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), +/* This entry is needed because the device reports Sub=ff */ +UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500, + "Sony", + "DSC-T1", + US_SC_8070, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), + + /* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", -- cgit v1.2.3 From cf3b38fd017b5b17f0ac5a672439bbbd292eaa4e Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Wed, 25 Feb 2004 22:18:20 -0800 Subject: [PATCH] USB Storage: Fix for Fuji Finepix 1400 This patch changes some error checking so that some bogus devices (like the Fuji Finepix 1400) will work. This is basically relaxing a test on a field that the spec says "should always be zero" --- drivers/usb/storage/transport.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 67b66c7221f6..2f1a7045608f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -809,15 +809,19 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) } /* If not UFI, we interpret the data as a result code - * The first byte should always be a 0x0 - * The second byte & 0x0F should be 0x0 for good, otherwise error + * The first byte should always be a 0x0. + * + * Some bogus devices don't follow that rule. They stuff the ASC + * into the first byte -- so if it's non-zero, call it a failure. */ if (us->iobuf[0]) { - US_DEBUGP("CBI IRQ data showed reserved bType %d\n", + US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n", us->iobuf[0]); - return USB_STOR_TRANSPORT_ERROR; + goto Failed; + } + /* The second byte & 0x0F should be 0x0 for good, otherwise error */ switch (us->iobuf[1] & 0x0F) { case 0x00: return USB_STOR_TRANSPORT_GOOD; -- cgit v1.2.3 From 258e21c11284456467f92216c87b547759f746da Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Wed, 25 Feb 2004 22:18:38 -0800 Subject: [PATCH] USB Storage: Remove unneeded macro This one-liner removes an unneeded macro. --- drivers/usb/storage/usb.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 2615d0f3fa16..2dee62aa5fe8 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -176,6 +176,5 @@ extern void fill_inquiry_response(struct us_data *us, * single queue element srb for write access */ #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) -#define sg_address(psg) (page_address((psg).page) + (psg).offset) #endif -- cgit v1.2.3 From cf5f741128d4f5cde103b0587dddad86242b2158 Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Wed, 25 Feb 2004 22:18:57 -0800 Subject: [PATCH] USB Storage: tighten sense-clearing code This patch tightens up the conditions under which an auto-sense will be cleared. It also fixes the comment associated with the code. --- drivers/usb/storage/transport.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 2f1a7045608f..c0c05910fafb 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -563,9 +563,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) /* * If we're running the CB transport, which is incapable - * of determining status on its own, we need to auto-sense + * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices - * can signal data-in errors by stalling the bulk-in pipe. + * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && srb->sc_data_direction != SCSI_DATA_READ) { @@ -698,7 +698,11 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && - (srb->sense_buffer[2] & 0xf) == 0x0) { + /* Filemark 0, ignore EOM, ILI 0, no sense */ + (srb->sense_buffer[2] & 0xaf) == 0 && + /* No ASC or ASCQ */ + srb->sense_buffer[12] == 0 && + srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } -- cgit v1.2.3 From f93f12ec6e2d7bcdef69c24cb9f0b4763de27fac Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Feb 2004 22:19:13 -0800 Subject: [PATCH] USB Storage: remove unneeded debug message Nothing in life is assured... --- drivers/usb/storage/usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 383a72dd40eb..5c78db52e806 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -953,8 +953,6 @@ static int storage_probe(struct usb_interface *intf, scsi_scan_host(us->host); - printk(KERN_DEBUG - "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_DEBUG "USB Mass Storage device found at %d\n", us->pusb_dev->devnum); return 0; -- cgit v1.2.3 From 67d27ac4cda55c30166160257130c04d2be94c6a Mon Sep 17 00:00:00 2001 From: Michal Dobrzynski Date: Thu, 26 Feb 2004 20:11:07 -0800 Subject: [PATCH] USB: add IRTrans support to ftdi_sio driver --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ee4fa64334cb..4911679c5d4e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -286,6 +286,7 @@ static struct usb_device_id id_table_sio [] = { static struct usb_device_id id_table_8U232AM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, @@ -358,6 +359,7 @@ static struct usb_device_id id_table_8U232AM [] = { static struct usb_device_id id_table_FT232BM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, @@ -451,6 +453,7 @@ static struct usb_device_id id_table_HE_TIRA1 [] = { static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index a69eb0d5b069..2177e46e6749 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -30,6 +30,8 @@ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ -- cgit v1.2.3 From d890d1a6b1cc778e00935266472b13d5c513ad88 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 26 Feb 2004 20:11:31 -0800 Subject: [PATCH] USB: Fix for kl5kusb105 driver I tried using the kl5kusb105 driver for a 3Com PalmConnect USB device I had lying around. It oopses during device detection. There is a nested loop using the same loop counter as the outer loop - causing the code after the nested loop is first executed to have an invalid counter. The counter is then used as an array index, causing a NULL deref. Fix attached. --- drivers/usb/serial/kl5kusb105.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 1ebc09851dcd..cb52024bfbc5 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -273,6 +273,7 @@ static int klsi_105_startup (struct usb_serial *serial) /* allocate the private data structure */ for (i=0; inum_ports; i++) { + int j; priv = kmalloc(sizeof(struct klsi_105_private), GFP_KERNEL); if (!priv) { @@ -293,10 +294,10 @@ static int klsi_105_startup (struct usb_serial *serial) usb_set_serial_port_data(serial->port[i], priv); spin_lock_init (&priv->lock); - for (i=0; iwrite_urb_pool[i] = urb; + priv->write_urb_pool[j] = urb; if (urb == NULL) { err("No more urbs???"); continue; -- cgit v1.2.3 From 810057e0c4ff01a5655f024b0ff1d1e35f2a939e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 26 Feb 2004 20:11:54 -0800 Subject: [PATCH] USB Storage: Remove Minolta Dimage 7i from unusual_devs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Fri, 27 Feb 2004, Lenar Lõhmus wrote: > Hi, > > Got this: > > usb 3-1: new full speed USB device using address 3 > usb-storage: This device (0686,400b,0001 S 06 P 50) has an unneeded SubClass entry in unusual_devs.h > Please send a copy of this message to Well, Martin Pool notwithstanding (see http://marc.theaimsgroup.com/?l=linux-usb-devel&m=107642806303815&w=2 ), it sure looks like this doesn't need an unusual_devs.h entry. Greg, please apply this patch. --- drivers/usb/storage/unusual_devs.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d1bfb3d02d30..219bdb8028b9 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -448,12 +448,6 @@ UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, US_SC_SCSI, US_PR_DEVICE, NULL, 0 ), -UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001, - "Minolta", - "DiMAGE 7i", - US_SC_SCSI, US_PR_DEVICE, NULL, - 0 ), - UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001, "Minolta", "DiMAGE 7Hi", -- cgit v1.2.3 From 545464bcbc7a33aa89aa0ebe60bd916a81eb7cf1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 Feb 2004 20:12:12 -0800 Subject: [PATCH] USB: usbnet learns about Zaurus C-860 New Zaurus ID, from Sven Trampel --- drivers/usb/net/usbnet.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 142e45f3ea9d..4104df1af9d3 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -3314,6 +3314,15 @@ static const struct usb_device_id products [] = { .bInterfaceSubClass = 0x0a, .bInterfaceProtocol = 0x00, .driver_info = (unsigned long) &zaurus_pxa_info, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9050, /* C-860 */ + .bInterfaceClass = 0x02, + .bInterfaceSubClass = 0x0a, + .bInterfaceProtocol = 0x00, + .driver_info = (unsigned long) &zaurus_pxa_info, }, #endif -- cgit v1.2.3 From 01ddaf6230a1ac2b1c50f5ebbce052c043687e01 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 Feb 2004 20:12:28 -0800 Subject: [PATCH] USB Gadget: gadget config buffer utilities Adds two new gadget-side utility functions, to support a declarative style of managing usb configuration descriptors. The functions fill buffers from null-terminated vectors of usb descriptors, which are simple to build or update. The "ethernet" gadget driver currently has the most interesting config descriptors. This uses those functions to replace some complex code with simpler static declarations; result, it's cleaner. (And it'll be easier to add RNDIS configurations later, too.) Memory savings (or cost, depending on config) was less than 50 bytes; nothing worth worrying about. --- Documentation/DocBook/gadget.tmpl | 1 + drivers/usb/gadget/Makefile | 2 +- drivers/usb/gadget/config.c | 116 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/ether.c | 123 ++++++++++++++++---------------------- include/linux/usb_gadget.h | 11 ++++ 5 files changed, 179 insertions(+), 74 deletions(-) create mode 100644 drivers/usb/gadget/config.c diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index af92fe5208d7..f07e73a41062 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -454,6 +454,7 @@ but some optional utilities are provided to simplify common tasks. !Edrivers/usb/gadget/usbstring.c +!Edrivers/usb/gadget/config.c diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 8c332a4dee10..ed21782ee859 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o # USB gadget drivers # g_zero-objs := zero.o usbstring.o -g_ether-objs := ether.o usbstring.o +g_ether-objs := ether.o usbstring.o config.o g_serial-objs := serial.o usbstring.o gadgetfs-objs := inode.o usbstring.o g_file_storage-objs := file_storage.o usbstring.o diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c new file mode 100644 index 000000000000..3437b92f66cd --- /dev/null +++ b/drivers/usb/gadget/config.c @@ -0,0 +1,116 @@ +/* + * usb/gadget/config.c -- simplify building config descriptors + * + * Copyright (C) 2003 David Brownell + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include + + +/** + * usb_descriptor_fillbuf - fill buffer with descriptors + * @buf: Buffer to be filled + * @buflen: Size of buf + * @src: Array of descriptor pointers, terminated by null pointer. + * + * Copies descriptors into the buffer, returning the length or a + * negative error code if they can't all be copied. Useful when + * assembling descriptors for an associated set of interfaces used + * as part of configuring a composite device; or in other cases where + * sets of descriptors need to be marshaled. + */ +int +usb_descriptor_fillbuf(void *buf, unsigned buflen, + const struct usb_descriptor_header **src) +{ + u8 *dest = buf; + + if (!src) + return -EINVAL; + + /* fill buffer from src[] until null descriptor ptr */ + for (; 0 != *src; src++) { + unsigned len = (*src)->bLength; + + if (len > buflen); + return -EINVAL; + memcpy(dest, *src, len); + buflen -= len; + dest += len; + } + return dest - (u8 *)buf; +} + + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} + diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 7c98cb03a2b2..1ab0afe74f02 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -607,6 +607,25 @@ fs_sink_desc = { .wMaxPacketSize = __constant_cpu_to_le16 (64), }; +static const struct usb_descriptor_header *fs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &fs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_sink_desc, + 0, +}; + #ifdef HIGHSPEED /* @@ -660,6 +679,25 @@ dev_qualifier = { .bNumConfigurations = 1, }; +static const struct usb_descriptor_header *hs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &hs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -704,86 +742,25 @@ static struct usb_gadget_strings stringtab = { static int config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { - const unsigned config_len = USB_DT_CONFIG_SIZE -#ifdef DEV_CONFIG_CDC - + 2 * USB_DT_INTERFACE_SIZE - + sizeof header_desc - + sizeof union_desc - + sizeof ether_desc -#ifdef EP_STATUS_NUM - + USB_DT_ENDPOINT_SIZE -#endif -#endif /* DEV_CONFIG_CDC */ - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; - + int len; + const struct usb_descriptor_header **function = fs_function; #ifdef HIGHSPEED - int hs; -#endif - /* a single configuration must always be index 0 */ - if (index > 0) - return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; + int hs = (speed == USB_SPEED_HIGH); - /* config (or other speed config) */ - memcpy (buf, ð_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#endif - -#ifdef DEV_CONFIG_CDC - /* control interface, class descriptors, optional status endpoint */ - memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - memcpy (buf, &header_desc, sizeof header_desc); - buf += sizeof header_desc; - memcpy (buf, &union_desc, sizeof union_desc); - buf += sizeof union_desc; - memcpy (buf, ðer_desc, sizeof ether_desc); - buf += sizeof ether_desc; - -#ifdef EP_STATUS_NUM -#ifdef HIGHSPEED if (hs) - memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE); - else -#endif /* HIGHSPEED */ - memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; -#endif /* EP_STATUS_NUM */ - - /* default data altsetting has no endpoints */ - memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#endif /* DEV_CONFIG_CDC */ - - /* the "real" data interface has two endpoints */ - memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#ifdef HIGHSPEED - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + function = hs_function; #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - return config_len; + /* a single configuration must always be index 0 */ + if (index > 0) + return -EINVAL; + len = usb_gadget_config_buf (ð_config, buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 1cfb33ebf348..78c8382b6398 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -716,6 +716,17 @@ struct usb_gadget_strings { /* put descriptor for string with that id into buf (buflen >= 256) */ int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 03e4f4ae4133b7f213830515149ec1713765f91c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 Feb 2004 20:12:45 -0800 Subject: [PATCH] USB: EHCI and full-speed ISO-OUT This is a minor update to the patch I sent out about a week ago. The key change is to use the I/O watchdog while doing ISO streaming. Bernd Porr reports that a VT8235 system needs that; it seems like IDE activity can interfere with the delivery of USB IRQs. EHCI periodic scheduling updates. - Initial version of full speed ISO transaction support. This should handle OUT transactions, such as those for usb speakers. For now, it's controlled using an EXPERIMENTAL config option: * I've run into interesting differences in how different USB 2.0 hub silicon (the transaction translators) handle some older audio devices. Needs more investigation. * Interrupt transfer scheduling doesn't yet cope well with schedules where every slot already has activity. For now, don't plug in devices like hubs, mice, or keyboards while EHCI is streaming. - Protect freelist for highspeed ITDs, using spinlock. Could be an issue for some drivers. - Kick in the I/O watchdog timer (5 msec) for periodic transfers. In this case, IDE activity on a VT8235 lost the IRQs which should have kept the ISO stream active. Queues shorter than 5 msec are not going to work on all USB hosts. - Simplified the ISO scheduler: doesn't attempt to re-schedule after lossage, or to short-circuit scanning. (Rescheduling will probably come back later ... for now, the "hard" error here is highlighting problems that need attention.) --- drivers/usb/host/Kconfig | 9 + drivers/usb/host/ehci-dbg.c | 6 +- drivers/usb/host/ehci-hcd.c | 8 +- drivers/usb/host/ehci-sched.c | 525 +++++++++++++++++++++++++++++++++++------- drivers/usb/host/ehci.h | 14 +- 5 files changed, 468 insertions(+), 94 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 677aebe60996..55ec90a82ed6 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -29,6 +29,15 @@ config USB_EHCI_HCD To compile this driver as a module, choose M here: the module will be called ehci-hcd. +config USB_EHCI_SPLIT_ISO + bool "Full speed ISO transactions (EXPERIMENTAL)" + depends on USB_EHCI_HCD && EXPERIMENTAL + default n + ---help--- + This code is new and hasn't been used with many different + EHCI or USB 2.0 transaction translator implementations. + It should work for ISO-OUT transfers, like audio. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index e354a830d815..989a37804491 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -579,7 +579,11 @@ show_periodic (struct class_device *class_dev, char *buf) break; case Q_TYPE_SITD: temp = scnprintf (next, size, - " sitd/%p", p.sitd); + " sitd%d-%04x/%p", + p.sitd->stream->interval, + le32_to_cpup (&p.sitd->hw_uframe) + & 0x0000ffff, + p.sitd); tag = Q_NEXT_TYPE (p.sitd->hw_next); p = p.sitd->sitd_next; break; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5552e96182fc..ad0084f2af50 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -106,8 +106,6 @@ static const char hcd_name [] = "ehci_hcd"; #undef EHCI_VERBOSE_DEBUG #undef EHCI_URB_TRACE -// #define have_split_iso - #ifdef DEBUG #define EHCI_STATS #endif @@ -676,6 +674,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. */ if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0)) timer_action (ehci, TIMER_IO_WATCHDOG); @@ -796,13 +795,8 @@ static int ehci_urb_enqueue ( case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) return itd_submit (ehci, urb, mem_flags); -#ifdef have_split_iso else return sitd_submit (ehci, urb, mem_flags); -#else - dbg ("no split iso support yet"); - return -ENOSYS; -#endif /* have_split_iso */ } } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 5ffb743bb87e..e067274efeb5 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -53,14 +53,10 @@ periodic_next_shadow (union ehci_shadow *periodic, int tag) return &periodic->fstn->fstn_next; case Q_TYPE_ITD: return &periodic->itd->itd_next; -#ifdef have_split_iso - case Q_TYPE_SITD: + // case Q_TYPE_SITD: + default: return &periodic->sitd->sitd_next; -#endif /* have_split_iso */ } - dbg ("BAD shadow %p tag %d", periodic->ptr, tag); - // BUG (); - return 0; } /* returns true after successful unlink */ @@ -133,7 +129,6 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; -#ifdef have_split_iso case Q_TYPE_SITD: /* is it in the S-mask? (count SPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { @@ -154,7 +149,6 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; -#endif /* have_split_iso */ default: BUG (); } @@ -229,7 +223,8 @@ static int tt_no_collision ( if (same_tt (dev, here.itd->urb->dev)) { u16 mask; - mask = le32_to_cpu (here.sitd->hw_uframe); + mask = le32_to_cpu (here.sitd + ->hw_uframe); /* FIXME assumes no gap for IN! */ mask |= mask >> 8; if (mask & uf_mask) @@ -237,7 +232,7 @@ static int tt_no_collision ( } type = Q_NEXT_TYPE (here.qh->hw_next); here = here.sitd->sitd_next; - break; + continue; // case Q_TYPE_FSTN: default: ehci_dbg (ehci, @@ -698,12 +693,27 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) // BUG_ON (!list_empty(&stream->td_list)); while (!list_empty (&stream->free_list)) { - struct ehci_itd *itd; - - itd = list_entry (stream->free_list.next, - struct ehci_itd, itd_list); - list_del (&itd->itd_list); - dma_pool_free (ehci->itd_pool, itd, itd->itd_dma); + struct list_head *entry; + + entry = stream->free_list.next; + list_del (entry); + + /* knows about ITD vs SITD */ + if (stream->highspeed) { + struct ehci_itd *itd; + + itd = list_entry (entry, struct ehci_itd, + itd_list); + dma_pool_free (ehci->itd_pool, itd, + itd->itd_dma); + } else { + struct ehci_sitd *sitd; + + sitd = list_entry (entry, struct ehci_sitd, + sitd_list); + dma_pool_free (ehci->sitd_pool, sitd, + sitd->sitd_dma); + } } is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; @@ -858,6 +868,7 @@ itd_urb_transaction ( int i; unsigned num_itds; struct ehci_iso_sched *sched; + unsigned long flags; sched = iso_sched_alloc (urb->number_of_packets, mem_flags); if (unlikely (sched == 0)) @@ -871,6 +882,7 @@ itd_urb_transaction ( num_itds = urb->number_of_packets; /* allocate/init ITDs */ + spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < num_itds; i++) { /* free_list.next might be cache-hot ... but maybe @@ -884,8 +896,14 @@ itd_urb_transaction ( list_del (&itd->itd_list); itd_dma = itd->itd_dma; } else + itd = 0; + + if (!itd) { + spin_unlock_irqrestore (&ehci->lock, flags); itd = dma_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma); + spin_lock_irqsave (&ehci->lock, flags); + } if (unlikely (0 == itd)) { iso_sched_free (stream, sched); @@ -895,6 +913,7 @@ itd_urb_transaction ( itd->itd_dma = itd_dma; list_add (&itd->itd_list, &sched->td_list); } + spin_unlock_irqrestore (&ehci->lock, flags); /* temporarily store schedule info in hcpriv */ urb->hcpriv = sched; @@ -909,11 +928,11 @@ itd_slot_ok ( struct ehci_hcd *ehci, u32 mod, u32 uframe, - u32 end, u8 usecs, u32 period ) { + uframe %= period; do { /* can't commit more than 80% periodic == 100 usec */ if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) @@ -922,8 +941,7 @@ itd_slot_ok ( /* we know urb->interval is 2^N uframes */ uframe += period; - uframe %= mod; - } while (uframe != end); + } while (uframe < mod); return 1; } @@ -933,7 +951,6 @@ sitd_slot_ok ( u32 mod, struct ehci_iso_stream *stream, u32 uframe, - u32 end, struct ehci_iso_sched *sched, u32 period_uframes ) @@ -952,12 +969,20 @@ sitd_slot_ok ( */ /* check bandwidth */ + uframe %= period_uframes; do { u32 max_used; frame = uframe >> 3; uf = uframe & 7; + /* tt must be idle for start(s), any gap, and csplit. + * assume scheduling slop leaves 10+% for control/bulk. + */ + if (!tt_no_collision (ehci, period_uframes << 3, + stream->udev, frame, mask)) + return 0; + /* check starts (OUT uses more than one) */ max_used = 100 - stream->usecs; for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { @@ -969,25 +994,19 @@ sitd_slot_ok ( if (stream->c_usecs) { max_used = 100 - stream->c_usecs; do { - /* tt is busy in the gap before CSPLIT */ tmp = 1 << uf; - mask |= tmp; tmp <<= 8; - if (stream->raw_mask & tmp) - break; + if ((stream->raw_mask & tmp) == 0) + continue; + if (periodic_usecs (ehci, frame, uf) + > max_used) + return 0; } while (++uf < 8); - if (periodic_usecs (ehci, frame, uf) > max_used) - return 0; } /* we know urb->interval is 2^N uframes */ uframe += period_uframes; - uframe %= mod; - } while (uframe != end); - - /* tt must be idle for start(s), any gap, and csplit */ - if (!tt_no_collision (ehci, period_uframes, stream->udev, frame, mask)) - return 0; + } while (uframe < mod); stream->splits = stream->raw_mask << (uframe & 7); cpu_to_le32s (&stream->splits); @@ -1014,7 +1033,7 @@ iso_stream_schedule ( struct ehci_iso_stream *stream ) { - u32 now, start, end, max, period; + u32 now, start, max, period; int status; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; @@ -1036,8 +1055,6 @@ iso_stream_schedule ( /* when's the last uframe this urb could start? */ max = now + mod; - max -= sched->span; - max -= 8 * SCHEDULE_SLOP; /* typical case: reuse current schedule. stream is still active, * and no gaps from host falling behind (irq delays etc) @@ -1046,9 +1063,11 @@ iso_stream_schedule ( start = stream->next_uframe; if (start < now) start += mod; - if (likely (start < max)) + if (likely ((start + sched->span) < max)) goto ready; - /* else fell behind; try to reschedule */ + /* else fell behind; someday, try to reschedule */ + status = -EL2NSYNC; + goto fail; } /* need to schedule; when's the next (u)frame we could start? @@ -1059,63 +1078,40 @@ iso_stream_schedule ( */ start = SCHEDULE_SLOP * 8 + (now & ~0x07); start %= mod; - end = start; + stream->next_uframe = start; /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ period = urb->interval; if (!stream->highspeed) period <<= 3; - if (max > (start + period)) - max = start + period; - /* hack: account for itds already scheduled to this endpoint */ - if (list_empty (&stream->td_list)) - end = max; - - /* within [start..max] find a uframe slot with enough bandwidth */ - end %= mod; - do { + /* find a uframe slot with enough bandwidth */ + for (; start < (stream->next_uframe + period); start++) { int enough_space; /* check schedule: enough space? */ if (stream->highspeed) - enough_space = itd_slot_ok (ehci, mod, start, end, + enough_space = itd_slot_ok (ehci, mod, start, stream->usecs, period); else { if ((start % 8) >= 6) continue; enough_space = sitd_slot_ok (ehci, mod, stream, - start, end, sched, period); + start, sched, period); } - /* (re)schedule it here if there's enough bandwidth */ + /* schedule it here if there's enough bandwidth */ if (enough_space) { - start %= mod; - if (unlikely (!list_empty (&stream->td_list))) { - /* host fell behind ... maybe irq latencies - * delayed this request queue for too long. - */ - stream->rescheduled++; - dev_dbg (&urb->dev->dev, - "iso%d%s %d.%d skip %d.%d\n", - stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) - ? "in" : "out", - stream->next_uframe >> 3, - stream->next_uframe & 0x7, - start >> 3, start & 0x7); - } - stream->next_uframe = start; + stream->next_uframe = start % mod; goto ready; } - - } while (++start < max); + } /* no room in the schedule */ - ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n", + ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", list_empty (&stream->td_list) ? "" : "re", - urb, now, end, max); + urb, now, max); status = -ENOSPC; fail: @@ -1260,6 +1256,7 @@ itd_link_urb ( iso_sched_free (stream, iso_sched); urb->hcpriv = 0; + timer_action (ehci, TIMER_IO_WATCHDOG); if (unlikely (!ehci->periodic_sched++)) return enable_periodic (ehci); return 0; @@ -1404,18 +1401,392 @@ done: return status; } -#ifdef have_split_iso +#ifdef CONFIG_USB_EHCI_SPLIT_ISO /*-------------------------------------------------------------------------*/ /* - * "Split ISO TDs" ... used for USB 1.1 devices going through - * the TTs in USB 2.0 hubs. - * - * FIXME not yet implemented + * "Split ISO TDs" ... used for USB 1.1 devices going through the + * TTs in USB 2.0 hubs. These need microframe scheduling. */ -#endif /* have_split_iso */ +static inline void +sitd_sched_init ( + struct ehci_iso_sched *iso_sched, + struct ehci_iso_stream *stream, + struct urb *urb +) +{ + unsigned i; + dma_addr_t dma = urb->transfer_dma; + + /* how many frames are needed for these transfers */ + iso_sched->span = urb->number_of_packets * stream->interval; + + /* figure out per-frame sitd fields that we'll need later + * when we fit new sitds into the schedule. + */ + for (i = 0; i < urb->number_of_packets; i++) { + struct ehci_iso_packet *packet = &iso_sched->packet [i]; + unsigned length; + dma_addr_t buf; + u32 trans; + + length = urb->iso_frame_desc [i].length & 0x03ff; + buf = dma + urb->iso_frame_desc [i].offset; + + trans = SITD_STS_ACTIVE; + if (((i + 1) == urb->number_of_packets) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) + trans |= SITD_IOC; + trans |= length << 16; + packet->transaction = cpu_to_le32 (trans); + + /* might need to cross a buffer page within a td */ + packet->bufp = buf; + buf += length; + packet->buf1 = buf & ~0x0fff; + if (packet->buf1 != (buf & ~(u64)0x0fff)) + packet->cross = 1; + + /* OUT uses multiple start-splits */ + if (stream->bEndpointAddress & USB_DIR_IN) + continue; + length = 1 + (length / 188); + packet->buf1 |= length; + if (length > 1) /* BEGIN vs ALL */ + packet->buf1 |= 1 << 3; + } +} + +static int +sitd_urb_transaction ( + struct ehci_iso_stream *stream, + struct ehci_hcd *ehci, + struct urb *urb, + int mem_flags +) +{ + struct ehci_sitd *sitd; + dma_addr_t sitd_dma; + int i; + struct ehci_iso_sched *iso_sched; + unsigned long flags; + + iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags); + if (iso_sched == 0) + return -ENOMEM; + + sitd_sched_init (iso_sched, stream, urb); + + /* allocate/init sITDs */ + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < urb->number_of_packets; i++) { + + /* NOTE: for now, we don't try to handle wraparound cases + * for IN (using sitd->hw_backpointer, like a FSTN), which + * means we never need two sitds for full speed packets. + */ + + /* free_list.next might be cache-hot ... but maybe + * the HC caches it too. avoid that issue for now. + */ + + /* prefer previously-allocated sitds */ + if (!list_empty(&stream->free_list)) { + sitd = list_entry (stream->free_list.prev, + struct ehci_sitd, sitd_list); + list_del (&sitd->sitd_list); + sitd_dma = sitd->sitd_dma; + } else + sitd = 0; + + if (!sitd) { + spin_unlock_irqrestore (&ehci->lock, flags); + sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags, + &sitd_dma); + spin_lock_irqsave (&ehci->lock, flags); + } + + if (!sitd) { + iso_sched_free (stream, iso_sched); + spin_unlock_irqrestore (&ehci->lock, flags); + return -ENOMEM; + } + memset (sitd, 0, sizeof *sitd); + sitd->sitd_dma = sitd_dma; + list_add (&sitd->sitd_list, &iso_sched->td_list); + } + + /* temporarily store schedule info in hcpriv */ + urb->hcpriv = iso_sched; + urb->error_count = 0; + + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +sitd_patch ( + struct ehci_iso_stream *stream, + struct ehci_sitd *sitd, + struct ehci_iso_sched *iso_sched, + unsigned index +) +{ + struct ehci_iso_packet *uf = &iso_sched->packet [index]; + u64 bufp = uf->bufp; + + sitd->hw_next = EHCI_LIST_END; + sitd->hw_fullspeed_ep = stream->address; + sitd->hw_uframe = stream->splits; + sitd->hw_results = uf->transaction; + sitd->hw_backpointer = EHCI_LIST_END; + + bufp = uf->bufp; + sitd->hw_buf [0] = cpu_to_le32 (bufp); + sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32); + + sitd->hw_buf [1] = cpu_to_le32 (uf->buf1); + if (uf->cross) { + bufp += 4096; + sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32); + } + sitd->index = index; +} + +static inline void +sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd) +{ + /* note: sitd ordering could matter (CSPLIT then SSPLIT) */ + sitd->sitd_next = ehci->pshadow [frame]; + sitd->hw_next = ehci->periodic [frame]; + ehci->pshadow [frame].sitd = sitd; + sitd->frame = frame; + wmb (); + ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD; +} + +/* fit urb's sitds into the selected schedule slot; activate as needed */ +static int +sitd_link_urb ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned mod, + struct ehci_iso_stream *stream +) +{ + int packet; + unsigned next_uframe; + struct ehci_iso_sched *sched = urb->hcpriv; + struct ehci_sitd *sitd; + + next_uframe = stream->next_uframe; + + if (list_empty(&stream->td_list)) { + /* usbfs ignores TT bandwidth */ + hcd_to_bus (&ehci->hcd)->bandwidth_allocated + += stream->bandwidth; + ehci_vdbg (ehci, + "sched dev%s ep%d%s-iso [%d] %dms/%04x\n", + urb->dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + (next_uframe >> 3) % ehci->periodic_size, + stream->interval, le32_to_cpu (stream->splits)); + stream->start = jiffies; + } + hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++; + + /* fill sITDs frame by frame */ + for (packet = 0, sitd = 0; + packet < urb->number_of_packets; + packet++) { + + /* ASSERT: we have all necessary sitds */ + BUG_ON (list_empty (&sched->td_list)); + + /* ASSERT: no itds for this endpoint in this frame */ + + sitd = list_entry (sched->td_list.next, + struct ehci_sitd, sitd_list); + list_move_tail (&sitd->sitd_list, &stream->td_list); + sitd->stream = iso_stream_get (stream); + sitd->urb = usb_get_urb (urb); + + sitd_patch (stream, sitd, sched, packet); + sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size, + sitd); + + next_uframe += stream->interval << 3; + stream->depth += stream->interval << 3; + } + stream->next_uframe = next_uframe % mod; + + /* don't need that schedule data any more */ + iso_sched_free (stream, sched); + urb->hcpriv = 0; + + timer_action (ehci, TIMER_IO_WATCHDOG); + if (!ehci->periodic_sched++) + return enable_periodic (ehci); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ + | SITD_STS_XACT | SITD_STS_MMF | SITD_STS_STS) + +static unsigned +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + struct pt_regs *regs +) { + struct urb *urb = sitd->urb; + struct usb_iso_packet_descriptor *desc; + u32 t; + int urb_index = -1; + struct ehci_iso_stream *stream = sitd->stream; + struct usb_device *dev; + + urb_index = sitd->index; + desc = &urb->iso_frame_desc [urb_index]; + t = le32_to_cpup (&sitd->hw_results); + + /* report transfer status */ + if (t & SITD_ERRS) { + urb->error_count++; + if (t & SITD_STS_DBE) + desc->status = usb_pipein (urb->pipe) + ? -ENOSR /* hc couldn't read */ + : -ECOMM; /* hc couldn't write */ + else if (t & SITD_STS_BABBLE) + desc->status = -EOVERFLOW; + else /* XACT, MMF, etc */ + desc->status = -EPROTO; + } else { + desc->status = 0; + desc->actual_length = desc->length - SITD_LENGTH (t); + } + + usb_put_urb (urb); + sitd->urb = 0; + sitd->stream = 0; + list_move (&sitd->sitd_list, &stream->free_list); + stream->depth -= stream->interval << 3; + iso_stream_put (ehci, stream); + + /* handle completion now? */ + if ((urb_index + 1) != urb->number_of_packets) + return 0; + + /* ASSERT: it's really the last sitd for this urb + list_for_each_entry (sitd, &stream->td_list, sitd_list) + BUG_ON (sitd->urb == urb); + */ + + /* give urb back to the driver */ + dev = usb_get_dev (urb->dev); + ehci_urb_done (ehci, urb, regs); + urb = 0; + + /* defer stopping schedule; completion can submit */ + ehci->periodic_sched--; + if (!ehci->periodic_sched) + (void) disable_periodic (ehci); + hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--; + + if (list_empty (&stream->td_list)) { + hcd_to_bus (&ehci->hcd)->bandwidth_allocated + -= stream->bandwidth; + ehci_vdbg (ehci, + "deschedule devp %s ep%d%s-iso\n", + dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); + } + iso_stream_put (ehci, stream); + usb_put_dev (dev); + + return 1; +} + + +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +{ + int status = -EINVAL; + unsigned long flags; + struct ehci_iso_stream *stream; + + // FIXME remove when csplits behave + if (usb_pipein(urb->pipe)) { + ehci_dbg (ehci, "no iso-IN split transactions yet\n"); + return -ENOMEM; + } + + /* Get iso_stream head */ + stream = iso_stream_find (ehci, urb); + if (stream == 0) { + ehci_dbg (ehci, "can't get iso stream\n"); + return -ENOMEM; + } + if (urb->interval != stream->interval) { + ehci_dbg (ehci, "can't change iso interval %d --> %d\n", + stream->interval, urb->interval); + goto done; + } + +#ifdef EHCI_URB_TRACE + ehci_dbg (ehci, + "submit %p dev%s ep%d%s-iso len %d\n", + urb, urb->dev->devpath, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + urb->transfer_buffer_length); +#endif + + /* allocate SITDs */ + status = sitd_urb_transaction (stream, ehci, urb, mem_flags); + if (status < 0) { + ehci_dbg (ehci, "can't init sitds\n"); + goto done; + } + + /* schedule ... need to lock */ + spin_lock_irqsave (&ehci->lock, flags); + status = iso_stream_schedule (ehci, urb, stream); + if (status == 0) + sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + spin_unlock_irqrestore (&ehci->lock, flags); + +done: + if (status < 0) + iso_stream_put (ehci, stream); + return status; +} + +#else + +static inline int +sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +{ + ehci_dbg (ehci, "split iso support is disabled\n"); + return -ENOSYS; +} + +static inline unsigned +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + struct pt_regs *regs +) { + ehci_err (ehci, "sitd_complete %p?\n", sitd); + return 0; +} + +#endif /* USB_EHCI_SPLIT_ISO */ /*-------------------------------------------------------------------------*/ @@ -1513,7 +1884,6 @@ restart: modified = itd_complete (ehci, q.itd, regs); q = *q_p; break; -#ifdef have_split_iso case Q_TYPE_SITD: if (q.sitd->hw_results & SITD_ACTIVE) { q_p = &q.sitd->sitd_next; @@ -1529,7 +1899,6 @@ restart: modified = sitd_complete (ehci, q.sitd, regs); q = *q_p; break; -#endif /* have_split_iso */ default: dbg ("corrupt type %d frame %d shadow %p", type, frame, q.ptr); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 349c635200de..5c6eef9674d6 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -492,16 +492,16 @@ struct ehci_itd { /* * EHCI Specification 0.95 Section 3.4 * siTD, aka split-transaction isochronous Transfer Descriptor - * ... describe low/full speed iso xfers through TT in hubs + * ... describe full speed iso xfers through TT in hubs * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) */ struct ehci_sitd { /* first part defined by EHCI spec */ u32 hw_next; /* uses bit field macros above - see EHCI 0.95 Table 3-8 */ - u32 hw_fullspeed_ep; /* see EHCI table 3-9 */ - u32 hw_uframe; /* see EHCI table 3-10 */ - u32 hw_results; /* see EHCI table 3-11 */ + u32 hw_fullspeed_ep; /* EHCI table 3-9 */ + u32 hw_uframe; /* EHCI table 3-10 */ + u32 hw_results; /* EHCI table 3-11 */ #define SITD_IOC (1 << 31) /* interrupt on completion */ #define SITD_PAGE (1 << 30) /* buffer 0/1 */ #define SITD_LENGTH(x) (0x3ff & ((x)>>16)) @@ -515,8 +515,8 @@ struct ehci_sitd { #define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE) - u32 hw_buf [2]; /* see EHCI table 3-12 */ - u32 hw_backpointer; /* see EHCI table 3-13 */ + u32 hw_buf [2]; /* EHCI table 3-12 */ + u32 hw_backpointer; /* EHCI table 3-13 */ u32 hw_buf_hi [2]; /* Appendix B */ /* the rest is HCD-private */ @@ -552,8 +552,6 @@ struct ehci_fstn { /*-------------------------------------------------------------------------*/ -#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) - #ifndef DEBUG #define STUB_DEBUG_FILES #endif /* DEBUG */ -- cgit v1.2.3 From 633788cb714f719d38c301510516f1da8e3e7bfb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Feb 2004 20:42:07 -0800 Subject: USB: delete unneeded scanner documentation. --- Documentation/usb/scanner.txt | 336 ------------------------------------------ 1 file changed, 336 deletions(-) delete mode 100644 Documentation/usb/scanner.txt diff --git a/Documentation/usb/scanner.txt b/Documentation/usb/scanner.txt deleted file mode 100644 index 337d3f9388d8..000000000000 --- a/Documentation/usb/scanner.txt +++ /dev/null @@ -1,336 +0,0 @@ -Copyright (C) 1999, 2000 David E. Nelson -Updated 2003 by Henning Meier-Geinitz - - -OVERVIEW - -This README addresses issues regarding how to configure the kernel to access a -USB scanner. Although the driver was originally conceived for USB HP -scanners, it's general enough so that it can be used with most other USB -scanners. Also, one can pass the USB Vendor and Product IDs using module -parameters for unknown scanners. - -There are two drivers for SCSI-over-USB scanners: -* The "hpusbscsi" module for Hewlett-Packard 53xx series, Hewlett-Packard 7400, - Minolta Scan Dual II, Minolta Elite II -* The "microtek" module for the Microtek Scanmaker X6 - -In addition to the kernel driver, user-space tools like SANE are necessary to -actually use the scanner. SANE ("Scanner Access Now Easy") provides drivers -for a variety of USB scanners. See the appropriate SANE man page for details, -e.g. man sane-usb and man sane-hp (for HP scanners). - -NOTE: Just because a product is detected by this driver does not mean that -applications exist that support the product. It's in the hopes that this will -allow developers a means to produce applications that will support the listed -USB products. - - -ADDITIONAL INFORMATION - -http://www.linux-usb.org/ (General information, mailing lists, links) -http://www.mostang.com/sane/ (SANE user-space tools) -http://www.meier-geinitz.de/kernel/ (USB scanner driver information and patches) - - -REQUIREMENTS - -A host with a USB port. Ideally, either a UHCI (Intel), OHCI (Compaq and -others) or EHCI hardware should work. - -Using "make menuconfig" or your preferred method for configuring the kernel, -select "Support for USB", "OHCI HCD/UHCI HCD/EHCI HCD" depending on your -hardware, "USB Scanner support", and "USB device filesystem". Compile and -install the modules (you may need to execute "depmod -a" to update the module -dependencies). If any of the USB sections were compiled into the kernel, a -reboot is necessary. NOTE: Updating the boot disk with "lilo" may also be -required. Testing was performed only as modules, YMMV. - -Up to 16 scanners can be connected/used simultaneously. If devfs support is -enabled, see next section. Otherwise, the device files must be created -manually if they don't exist yet, either by MAKEDEV or mknod. - -MAKEDEV method: - cd /dev - MAKEDEV usb - Check that the device files "/dev/usb/scanner0" - "/dev/usb/scanner15" have - been created. - -mknod method: - mknod /dev/usb/scanner0 c 180 48 - mknod /dev/usb/scanner1 c 180 49 - . - . - mknod /dev/usb/scanner15 c 180 63 - -Set appropriate permissions for /dev/usb/scanner[0-15] (don't forget -about group and world permissions). Both read and write permissions -are required for proper operation. For example: - chmod 666 /dev/usb/scanner0 - -Load the appropriate modules (if compiled as modules): - - modprobe ohci-hcd (or uhci-hcd, ehci-hcd) - modprobe scanner - - -DEVFS - -The later versions of the Linux kernel (2.4.8'ish) included a dynamic -device filesystem call "devfs". With devfs, there is no need to -create the device files as explained above; instead, they are -dynamically created for you. For USB Scanner, the device is created -in /dev/usb/scannerX where X can range from 0 to 15 depending on the -number of scanners connected to the system. - -To see if you have devfs, issue the command "cat /proc/filesytems". -If devfs is listed you should be ready to go. You should also have a -process running called "devfsd". In order to make sure, issue the -command "ps aux | grep '[d]evfsd'". - - -CONCLUSION - -That's it. SANE should now be able to access the device. To make sure the -device was detected, use "cat /proc/bus/usb/devices". Your scanner should be -listed and the line starting with "I:" should look similar to this example: - - I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=usbscanner - -The important part is "Driver=usbscanner". If it reads "Driver=(none)", the -USB scanner driver didn't recognize the scanner. Have a look at the MODULE -PARAMETERS section for what to do in this case. - -For more details on the format of "/proc/bus/usb/devices" see -Documentation/usb/proc_usb_info.txt. - - -MESSAGES - -usb_control/bulk_msg: timeout -- On occasions this message will appear -in "/var/adm/messages", on the console, or both depending on how -your system is configured. This is a side effect that scanners are -sometimes very slow at warming up and/or initializing. In most cases, -however, only several of these messages should appear and is generally -considered to be normal. - -excessive NAK's received -- This message should be considered abnormal -and generally indicates that the USB system is unable to communicate -with the scanner for some particular reason. - -probe_scanner: Undetected endpoint -- The USB Scanner driver is fairly -general when it comes to communicating to scanners. Unfortunately, -some vendors have designed their scanners in one way or another that -this driver doesn't account for. - -probe_scanner: Endpoint determination failed -- This means that the -driver is unable to detect a supported configuration for means to -communicate with the scanner. See also "probe_scanner: Undetected -endpoint". - -funky result -- Most of the time the data flow between the computer -and the scanner goes smoothly. However, due to whatever reason, -whether it be solar flares or stray neutrons, sometimes the -communications don't work as expected. The driver tries to handle -most types of errors but not all. When this message is seen, -something weird happened. Please contact the mailing list (see -CONTACT section for details). - - -MODULE PARAMETERS - -If you have a device that you wish to experiment with or try using -this driver with, but the Vendor and Product IDs are not coded in, -don't despair. If the driver was compiled as a module, you can pass -options to the driver. Simply add - - options scanner vendor=0x#### product=0x**** - -to the /etc/modprobe.conf file replacing the #'s and the *'s with the -correct IDs. The IDs can be retrieved from the messages file or -using "cat /proc/bus/usb/devices". - -If the default timeout is too low, i.e. there are frequent "timeout" messages, -you may want to increase the timeout manually by using the parameter -"read_timeout". The time is given in seconds. This is an example for -modprobe.conf with a timeout of 60 seconds: - - options scanner read_timeout=60 - -If the "scanner" module is already loaded into memory, it must be reloaded for -the module parameters to take effect. In essence, "rmmod scanner; modprobe -scanner" must be performed. - - -BUGS - -Just look at the list of fixes in the source files. - - -CONTACT - -For asking about problems and fixes, use the linux-usb-users mailing list. For -patches, linux-usb-devel should be used. Information on both lists can be -found on http://www.linux-usb.org/. - - -CHANGES - -- Amended for linux-2.5.54 -- Added information about read_timeout -- Added more details about /proc/bus/usb/devices -- Added/updated links -- Added pointers two "special" scanner drivers -- Reordering, spell-checking, formatting -- Used /dev/usb/scanner[0-15] instead of /dev/usbscanner[0-15] -- Removed some basic USB configuration stuff -- Added EHCI -- Removed some more references to HP -- Amended for linux-2.4.12 -- Updated devfs support -- Amended for linux-2.3.99-pre6-3 -- Appended hp_scan.c to end of this README -- Removed most references to HP -- Updated uhci/ohci host controller info -- Updated support for multiple scanner support -- Updated supported scanners list -- Updated usbdevfs info -- Spellcheck - - -HP TEST PROGRAM - -There is a small test program (hp_scan.c -- appended below) that can -be used to test the scanner device if it's an HP scanner that supports -SCL (Scanner Control Language). Known HP scanner that support SCL are -the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not* -supported since it does not understand SCL; it's also strongly -suspected that the 3300 and the PhotoSmart S20 are not SCL compliant. -Hp_scan.c's purpose is to test the driver without having to -retrieve/configure SANE. Hp_scan.c will scan the entire bed and put -the output into a file called "out.dat" in the current directory. The -data in the file is raw data so it's not very useful for imaging. - ---------------- snip -- hp_scan.c -- snip --------------- -/* - -This is a really crude attempt at writing a short test program. It's -mostly only to be used to test connectivity with USB HP scanners that -understand SCL. Currently, the supported models are 4100C, 5200C, -6200C, and the 6300C. Note that the 4200C is *NOT* acceptable. - -Copyright (C) David E. Nelson , 1999 - -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 -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -*/ - -#include -#include -#include -#include -#include - -/* - Gray Output produces about a 8945400 byte file. - Color Output produces a 26836200 byte file. - - To compile: gcc -o hp_scan hp_scan.c -*/ - -// #define COLOR /* Undef to scan GrayScale */ - -int send_cmd(int, const char *, int); -int read_cmd(int, char *, int); - -int -main(void) { - - ssize_t cnt = 0, total_cnt = 0; - - FILE *fpout; - - int fp; - int data_size = 32768; - - char *data; - - static char reset_cmd[] = {'\x1b','E'}; - -#ifdef COLOR - static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */ - static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */ -#else - static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */ - static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */ -#endif - - static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'}; - static char start_scan_cmd[] = {'\x1b','*','f','0','S'}; - - if(!(data=malloc(data_size))) { - perror("malloc failed"); - exit (1); - } - - if((fp=open("/dev/usb/scanner0", O_RDWR)) < 0) { - perror("Unable to open scanner device"); - exit (1); - } - - if((fpout=fopen("out.dat", "w+")) == NULL) { - perror("Unable to open output file"); - exit(1); - } - - send_cmd(fp, reset_cmd, sizeof(reset_cmd)); - send_cmd(fp, data_type_cmd, sizeof(data_type_cmd)); - send_cmd(fp, data_width_cmd, sizeof(data_width_cmd)); - send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd)); - - while ((cnt = read(fp, data, data_size)) > 0) { - printf("Read: %u\n", cnt); - if(fwrite(data, sizeof(char), cnt, fpout) < 0) { - perror("Write to output file failed"); - exit (1); - } - total_cnt += cnt; - } - if (cnt < 0) { - perror("Read from scanner failed"); - exit (1); - } - - printf("\nRead %lu bytes.\n", total_cnt); - - send_cmd(fp, reset_cmd, sizeof(reset_cmd)); - - close(fp); - fclose(fpout); - return (0); -} - -int -send_cmd(int fp, const char * cmd, int length) { - - int result; - int x; - - if((result = write(fp, cmd, length)) != length) { - printf ("Write warning: %d bytes requested, %d written\n"); - } else if (result < 0) { - perror ("send_cmd failure"); - exit (1); - } - return (result); -} - -int -read_cmd(int fp, char * response, int length) { - - return read(fp, response, length); - -} -- cgit v1.2.3 From ae34567299a2173f8562220f07c504c67c95d46a Mon Sep 17 00:00:00 2001 From: Torrey Hoffman Date: Thu, 26 Feb 2004 20:52:43 -0800 Subject: [PATCH] USB: add driver for ATI USB/RF remotes I've taken the old GATOS version of the ati_remote driver and done some cleanup/rework of it while porting to 2.6 kernels. --- drivers/usb/input/Kconfig | 14 + drivers/usb/input/Makefile | 1 + drivers/usb/input/ati_remote.c | 834 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 849 insertions(+) create mode 100644 drivers/usb/input/ati_remote.c diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index cc80ee683f68..d8cef28b1dcd 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -192,3 +192,17 @@ config USB_XPAD To compile this driver as a module, choose M here: the module will be called xpad. + +config USB_ATI_REMOTE + tristate "ATI USB RF remote control" + depends on USB && INPUT + ---help--- + Say Y here if you want to use one of ATI's USB remote controls. + These are RF remotes with USB receivers. They come with many of ATI's + All-In-Wonder video cards. This driver provides mouse pointer, left + and right mouse buttons, and maps all the other remote buttons to + keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote. + diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index c97542683296..864922b04619 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_XPAD) += xpad.o +obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c new file mode 100644 index 000000000000..e62b6f9bfc43 --- /dev/null +++ b/drivers/usb/input/ati_remote.c @@ -0,0 +1,834 @@ +/* + * USB ATI Remote support + * + * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman + * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev + * + * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including + * porting to the 2.6 kernel interfaces, along with other modification + * to better match the style of the existing usb/input drivers. However, the + * protocol and hardware handling is essentially unchanged from 2.1.1. + * + * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by + * Vojtech Pavlik. + * + * Changes: + * + * Feb 2004: Torrey Hoffman + * Version 2.2.0 + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Hardware & software notes + * + * These remote controls are distributed by ATI as part of their + * "All-In-Wonder" video card packages. The receiver self-identifies as a + * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". + * + * It is possible to use multiple receivers and remotes on multiple computers + * simultaneously by configuring them to use specific channels. + * + * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. + * Actually, it may even support more, at least in some revisions of the + * hardware. + * + * Each remote can be configured to transmit on one channel as follows: + * - Press and hold the "hand icon" button. + * - When the red LED starts to blink, let go of the "hand icon" button. + * - When it stops blinking, input the channel code as two digits, from 01 + * to 16, and press the hand icon again. + * + * The timing can be a little tricky. Try loading the module with debug=1 + * to have the kernel print out messages about the remote control number + * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. + * + * The driver has a "channel_mask" parameter. This bitmask specifies which + * channels will be ignored by the module. To mask out channels, just add + * all the 2^channel_number values together. + * + * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote + * ignore signals coming from remote controls transmitting on channel 4, but + * accept all other channels. + * + * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be + * ignored. + * + * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this + * parameter are unused. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Module and Version Information, Module Parameters + */ + +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define ATI_REMOTE_PRODUCT_ID 0x004 + +#define DRIVER_VERSION "2.2.0" +#define DRIVER_AUTHOR "Torrey Hoffman " +#define DRIVER_DESC "USB driver for ATI/X10 RF Remote Control" + +#define NAME_BUFSIZE 80 /* size of product name, path buffers */ +#define DATA_BUFSIZE 63 /* size of URB data buffers */ +#define ATI_INPUTNUM 1 /* Which input device to register as */ + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug; +#endif +module_param(debug, int, 444); +MODULE_PARM_DESC(debug, "Enable / disable debug messages"); + +unsigned long channel_mask = 0; +module_param(channel_mask, ulong, 444); +MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); + +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + +static struct usb_device_id ati_remote_table[] = { + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ati_remote_table); + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 + +/* Device initialization strings */ +static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; +static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; + +struct ati_remote { + struct input_dev idev; + struct usb_device *udev; + struct usb_interface *interface; + + struct urb *irq_urb; + struct urb *out_urb; + struct usb_endpoint_descriptor *endpoint_in; + struct usb_endpoint_descriptor *endpoint_out; + unsigned char *inbuf; + unsigned char *outbuf; + dma_addr_t inbuf_dma; + dma_addr_t outbuf_dma; + + int open; /* open counter */ + int present; /* device plugged in? */ + + unsigned char old_data[2]; /* Detect duplicate events */ + unsigned long old_jiffies; + unsigned long acc_jiffies; /* handle acceleration */ + + char name[NAME_BUFSIZE]; + char phys[NAME_BUFSIZE]; + + wait_queue_head_t wait; + int send_flags; +}; + +/* "Kinds" of messages sent from the hardware to the driver. */ +#define KIND_END 0 +#define KIND_LITERAL 1 /* Simply pass to input system */ +#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ +#define KIND_LU 3 /* Directional keypad diagonals - left up, */ +#define KIND_RU 4 /* right up, */ +#define KIND_LD 5 /* left down, */ +#define KIND_RD 6 /* right down */ +#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ + +/* Translation table from hardware messages to input events. */ +static struct +{ + short kind; + unsigned char data1, data2; + int type; + unsigned int code; + int value; +} ati_remote_tbl[] = +{ + /* Directional control pad axes */ + {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + /* Directional control pad diagonals */ + {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + + /* "Mouse button" buttons */ + {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + + /* Artificial "doubleclick" events are generated by the hardware. + * They are mapped to the "side" and "extra" mouse buttons here. */ + {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + + /* keyboard. */ + {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, + {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, + {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, + {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, + {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, + {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, + {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, + {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, + {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, + {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, + {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, + {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, + {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, + {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, + {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, + {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, + + /* "special" keys */ + {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ + {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ + {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ + {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1}, /* TV */ + {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1}, /* DVD */ + {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ + {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ + {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ + {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ + {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ + {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ + {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ + {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ + {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ + {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1}, /* "OK" */ + {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ + {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ + {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ + {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ + {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ + {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ + {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1}, /* ( >) */ + {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ + {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ + {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ + {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ + + {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} +}; + +/* Local function prototypes */ +static void ati_remote_dump (unsigned char *data, unsigned int actual_length); +static void ati_remote_delete (struct ati_remote *dev); +static int ati_remote_open (struct input_dev *inputdev); +static void ati_remote_close (struct input_dev *inputdev); +static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); +static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs); +static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs); +static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs); +static int ati_remote_initialize (struct ati_remote *ati_remote); +static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); +static void ati_remote_disconnect (struct usb_interface *interface); + +/* usb specific object to register with the usb subsystem */ +static struct usb_driver ati_remote_driver = { + .owner = THIS_MODULE, + .name = "ati_remote", + .probe = ati_remote_probe, + .disconnect = ati_remote_disconnect, + .id_table = ati_remote_table, +}; + +/* + * ati_remote_dump_input + */ +static void ati_remote_dump(unsigned char *data, unsigned int len) +{ + if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) + warn("Weird byte 0x%02x", data[0]); + else if (len == 4) + warn("Weird key %02x %02x %02x %02x", + data[0], data[1], data[2], data[3]); + else + warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", + len, data[0], data[1], data[2], data[3], data[4], data[5]); +} + +/* + * ati_remote_open + */ +static int ati_remote_open(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = inputdev->private; + + if (ati_remote->open++) + return 0; + + /* On first open, submit the read urb which was set up previously. */ + ati_remote->irq_urb->dev = ati_remote->udev; + if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { + err(" %s: usb_submit_urb failed!", __FUNCTION__); + ati_remote->open--; + return -EIO; + } + + return 0; +} + +/* + * ati_remote_close + */ +static void ati_remote_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = inputdev->private; + + if (ati_remote == NULL) { + dbg("%s - object is NULL !", __FUNCTION__); + return; + } + + if (ati_remote->open <= 0) + dbg("%s - ati_remote not open.", __FUNCTION__); + else + --ati_remote->open; + + /* If still present, disconnect will call delete. */ + if (!ati_remote->present && !ati_remote->open) + ati_remote_delete(ati_remote); +} + +/* + * ati_remote_irq_out + */ +static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + + if (urb->status) { + warn("output urb completion status %d received", urb->status); + return; + } + + ati_remote->send_flags |= SEND_FLAG_COMPLETE; + wmb(); + if (waitqueue_active(&ati_remote->wait)) + wake_up(&ati_remote->wait); +} + +/* + * ati_remote_sendpacket + * + * Used to send device initialization strings + */ +static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) +{ + DECLARE_WAITQUEUE(wait, current); + int timeout = HZ; /* 1 second */ + int retval = 0; + + /* Set up out_urb */ + memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); + ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); + + ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; + ati_remote->out_urb->dev = ati_remote->udev; + ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ati_remote->wait, &wait); + + retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL); + if (retval) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&ati_remote->wait, &wait); + dbg("sendpacket: usb_submit_urb failed: %d", retval); + return retval; + } + + while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) + && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) { + timeout = schedule_timeout(timeout); + rmb(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&ati_remote->wait, &wait); + usb_unlink_urb(ati_remote->out_urb); + + return retval; +} + +/* + * ati_remote_event_lookup + */ +static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) +{ + int i; + + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + /* + * Decide if the table entry matches the remote input. + */ + if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && + ((((ati_remote_tbl[i].data1 >> 4) - + (d1 >> 4) + rem) & 0x0f) == 0x0f) && + (ati_remote_tbl[i].data2 == d2)) + return i; + + } + return -1; +} + +/* + * ati_remote_report_input + */ +static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + unsigned char *data= ati_remote->inbuf; + struct input_dev *dev = &ati_remote->idev; + int index, acc; + int remote_num; + + /* Deal with strange looking inputs */ + if ( (urb->actual_length != 4) || (data[0] != 0x14) || + ((data[3] & 0x0f) != 0x00) ) { + ati_remote_dump(data, urb->actual_length); + return; + } + + /* Mask unwanted remote channels. */ + /* note: remote_num is 0-based, channel 1 selected on remote == 0 here */ + remote_num = (data[3] >> 4) & 0x0f; + if (channel_mask & (1 << (remote_num + 1))) { + dbg("Remote 0x02%x masked. mask = 0x%02lx", + remote_num, channel_mask); + return; + } + dbg("Remote channel 0x%02x: %02x%02x", remote_num, data[1], data[2]); + + /* Look up event code index in translation table */ + index = ati_remote_event_lookup(remote_num, data[1], data[2]); + if (index < 0) { + warn("Unknown key=%02x%02x", data[1], data[2]); + return; + } + + if (ati_remote_tbl[index].kind == KIND_LITERAL) { + input_regs(dev, regs); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value); + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + return; + } + + if (ati_remote_tbl[index].kind == KIND_FILTERED) { + /* Filter duplicate events which happen "too close" together, + * considered here to be anything less than a quarter second */ + if ((ati_remote->old_data[0] == data[1]) && + (ati_remote->old_data[1] == data[2]) && + ((ati_remote->old_jiffies + (HZ >> 2)) > jiffies)) { + ati_remote->old_jiffies = jiffies; + return; + } + + input_regs(dev, regs); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 1); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 0); + input_sync(dev); + + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + ati_remote->old_jiffies = jiffies; + return; + } + + /* + * Other event kinds are from the directional control pad, and have an + * acceleration factor applied to them. Without added acceleration, the + * control pad is pretty unusable. + * + * If elapsed time since last event is > 1/4 second, user "stopped", + * so reset acceleration. Otherwise, user is probably holding the control + * pad down, so we increase acceleration, ramping up over two seconds to + * a maximum speed. + */ + if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) { + acc = 1; + ati_remote->acc_jiffies = jiffies; + } + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = 1; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = 2; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = 3; + else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = 4; + else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = 6; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = 10; + else acc = 16; + + input_regs(dev, regs); + switch (ati_remote_tbl[index].kind) { + case KIND_ACCEL: + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value * acc); + break; + case KIND_LU: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_RU: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_LD: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, acc); + break; + case KIND_RD: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, acc); + break; + default: + dbg("ati_remote kind=%d", ati_remote_tbl[index].kind); + } + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; +} + +/* + * ati_remote_irq_in + */ +static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) +{ + struct ati_remote *ati_remote = urb->context; + int retval; + + switch (urb->status) + { + case 0: /* success */ + ati_remote_input_report(urb, regs); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + dbg("%s: urb error status (unlink?)", __FUNCTION__); + return; + default: /* error */ + dbg("%s: Nonzero urb status %d", __FUNCTION__, urb->status); + } + + retval = usb_submit_urb(urb, SLAB_ATOMIC); + if (retval) + err("%s: can't resubmit urb, %s-%s/input%d, status %d", + __FUNCTION__, ati_remote->udev->bus->bus_name, + ati_remote->udev->devpath, ATI_INPUTNUM, retval); +} + +/* + * ati_remote_delete + */ +static void ati_remote_delete(struct ati_remote *ati_remote) +{ + if (!ati_remote) return; + + if (ati_remote->irq_urb) + usb_unlink_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_unlink_urb(ati_remote->out_urb); + + if (ati_remote->irq_urb) + usb_free_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_free_urb(ati_remote->out_urb); + + if (ati_remote->inbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); + + if (ati_remote->outbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->outbuf_dma); + + kfree(ati_remote); +} + +static void ati_remote_input_init(struct ati_remote *ati_remote) +{ + struct input_dev *idev = &(ati_remote->idev); + int i; + + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | + BIT(BTN_SIDE) | BIT(BTN_EXTRA) ); + idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) + if (ati_remote_tbl[i].type == EV_KEY) + set_bit(ati_remote_tbl[i].code, idev->keybit); + + idev->private = ati_remote; + idev->open = ati_remote_open; + idev->close = ati_remote_close; + + idev->name = ati_remote->name; + idev->phys = ati_remote->phys; + + idev->id.bustype = BUS_USB; + idev->id.vendor = ati_remote->udev->descriptor.idVendor; + idev->id.product = ati_remote->udev->descriptor.idProduct; + idev->id.version = ati_remote->udev->descriptor.bcdDevice; +} + +static int ati_remote_initialize(struct ati_remote *ati_remote) +{ + struct usb_device *udev = ati_remote->udev; + int pipe, maxp; + + init_waitqueue_head(&ati_remote->wait); + + /* Set up irq_urb */ + pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, + maxp, ati_remote_irq_in, ati_remote, + ati_remote->endpoint_in->bInterval); + ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; + ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* Set up out_urb */ + pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, + maxp, ati_remote_irq_out, ati_remote, + ati_remote->endpoint_out->bInterval); + ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; + ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* send initialization strings */ + if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || + (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { + err("Initializing ati_remote hardware failed."); + return 1; + } + + return 0; +} + +/* + * ati_remote_probe + */ +static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct ati_remote *ati_remote = NULL; + struct usb_host_interface *iface_host; + int retval = -ENOMEM; + char path[64]; + char *buf = NULL; + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != ATI_REMOTE_VENDOR_ID) || + (udev->descriptor.idProduct != ATI_REMOTE_PRODUCT_ID)) { + return -ENODEV; + } + + /* Allocate and clear an ati_remote struct */ + if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL))) + return -ENOMEM; + memset(ati_remote, 0x00, sizeof (struct ati_remote)); + + iface_host = &interface->altsetting[interface->act_altsetting]; + if (iface_host->desc.bNumEndpoints != 2) { + dbg("Unexpected desc.bNumEndpoints."); + retval = -ENODEV; + goto error; + } + + ati_remote->endpoint_in = &(iface_host->endpoint[0].desc); + ati_remote->endpoint_out = &(iface_host->endpoint[1].desc); + ati_remote->udev = udev; + ati_remote->interface = interface; + + if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) { + dbg("Unexpected endpoint_in->bEndpointAddress."); + retval = -ENODEV; + goto error; + } + if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) { + dbg("Unexpected endpoint_in->bmAttributes."); + retval = -ENODEV; + goto error; + } + if (ati_remote->endpoint_in->wMaxPacketSize == 0) { + dbg("endpoint_in message size = 0?"); + retval = -ENODEV; + goto error; + } + if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL))) + goto error; + + /* Allocate URB buffers, URBs */ + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + goto error; + + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + goto error; + + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + goto error; + + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + goto error; + + usb_make_path(udev, path, NAME_BUFSIZE); + sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM); + if (udev->descriptor.iManufacturer && + (usb_string(udev, udev->descriptor.iManufacturer, buf, + NAME_BUFSIZE) > 0)) + strcat(ati_remote->name, buf); + + if (udev->descriptor.iProduct && + (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0)) + sprintf(ati_remote->name, "%s %s", ati_remote->name, buf); + + if (!strlen(ati_remote->name)) + sprintf(ati_remote->name, "USB ATI (X10) remote %04x:%04x", + ati_remote->idev.id.vendor, ati_remote->idev.id.product); + + /* Device Hardware Initialization */ + retval = ati_remote_initialize(ati_remote); + if (retval) + goto error; + + /* Set up and register input device */ + ati_remote_input_init(ati_remote); + input_register_device(&ati_remote->idev); + + info("Input registered: %s on %s", ati_remote->name, path); + info("USB (bus:dev)=(%d:%d)", udev->bus->busnum, udev->devnum); + + usb_set_intfdata(interface, ati_remote); + ati_remote->present = 1; + kfree(buf); + return 0; + +error: + if (buf) + kfree(buf); + + ati_remote_delete(ati_remote); + return retval; +} + +/* + * ati_remote_disconnect + */ +static void ati_remote_disconnect(struct usb_interface *interface) +{ + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + if (!ati_remote) { + warn("%s - null device?", __FUNCTION__); + return; + } + + input_unregister_device(&ati_remote->idev); + + /* Mark device as unplugged */ + ati_remote->present = 0; + + /* If device is still open, ati_remote_close will call delete. */ + if (!ati_remote->open) + ati_remote_delete(ati_remote); +} + +/* + * ati_remote_init + */ +static int __init ati_remote_init(void) +{ + int result; + + result = usb_register(&ati_remote_driver); + if (result) + err("usb_register error #%d", result); + else + info("USB registered " DRIVER_DESC " ver. " DRIVER_VERSION); + + return result; +} + +/* + * ati_remote_exit + */ +static void __exit ati_remote_exit(void) +{ + usb_deregister(&ati_remote_driver); +} + +/* + * module specification + */ + +module_init(ati_remote_init); +module_exit(ati_remote_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From d1831727c3266429693d9eaff3a2940e6713863d Mon Sep 17 00:00:00 2001 From: Trent Whaley Date: Thu, 26 Feb 2004 20:53:04 -0800 Subject: [PATCH] USB: kbtab.c (Jamstudio Tablet) with optional pressure I have altered kbtab.c a bit in anticipation of an XFree86 4.3 driver that can accept the pressure data (as a third axis) by listening on the event interface. I have set it so that if the option kb_pressure_click is -1 it reports pressure rather than clicks. --- drivers/usb/input/kbtab.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index c37912ab547f..beef425de482 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -74,12 +74,15 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) input_report_abs(dev, ABS_X, kbtab->x); input_report_abs(dev, ABS_Y, kbtab->y); - /*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/ /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ input_report_key(dev, BTN_RIGHT, data[0] & 0x02); - - input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); + + if( -1 == kb_pressure_click){ + input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); + } else { + input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); + }; input_sync(dev); -- cgit v1.2.3 From 1d491fecdbc04281ae79b0a47b273c2058f77e6c Mon Sep 17 00:00:00 2001 From: "Todd E. Johnson" Date: Thu, 26 Feb 2004 20:53:21 -0800 Subject: [PATCH] USB: add new USB Touchscreen Driver I have attached a patch which contains a driver and documentation for the MicroTouch (14-206) USB Capacitive Touchscreen controller. It based on some older code that I have been using for quite some time now (since 2.4.17). This new version has been completely re-written, and now uses Linux Input. Greg, It would be great to possibly get it into 2.6.4. Please let me know if I have it all wrong... Unfortunately, the X11 mouse driver only seems capable of handling relative data rather than absolute. Hopefully some one will create a suitable X11 driver capable of accepting absolute data from Linux Input. If anyone is aware of one, please let me know. Otherwise, I will most likely begin some work on a patch for GPM. Calibration support will be on the way soon, but I'm not sure of the best way to implement. Perhaps some abstract functions could come available in evdev which can call vendor specific commands for the calibration within this driver (and perhaps others). --- Documentation/usb/mtouchusb.txt | 85 +++++++++ drivers/usb/Makefile | 1 + drivers/usb/input/Kconfig | 12 ++ drivers/usb/input/Makefile | 1 + drivers/usb/input/mtouchusb.c | 391 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 490 insertions(+) create mode 100644 Documentation/usb/mtouchusb.txt create mode 100644 drivers/usb/input/mtouchusb.c diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt new file mode 100644 index 000000000000..f27200050ce9 --- /dev/null +++ b/Documentation/usb/mtouchusb.txt @@ -0,0 +1,85 @@ +CHANGES + +- Created based off of scanner & INSTALL from the original touchscreen + driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver) +- Amended for linux-2.4.18, then 2.4.19 + +- Complete rewrite using Linux Input in 2.6.3 + Unfortunately no calibration support at this time + + +DRIVER NOTES: + +Installation is simple, you only need to add Linux Input, Linux USB, and the +driver to the kernel. The driver can also be optionally built as a module. + +If you have another MicroTouch device that you wish to experiment with +or try using this driver with, but the Vendor and Product ID's are not +coded in, don't despair. If the driver was compiled as a module, you can +pass options to the driver. Simply try: + + /sbin/modprobe mtouchusb vendor=0x#### product=0x**** + +If it works, send me the iVendor & iProduct (or a patch) and I will add... + +This driver appears to be one of possible 2 Linux USB Input Touchscreen +drivers. Although 3M produces a binary only driver available for +download, I persist in updating this driver since I would like to use the +touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the +logical choice is to use Linux Imput. + +A little info about the MicroTouch USB controller (14-206): + +Y is inverted, and the device has a total possible resolution of 0 - 65535. + +Y is inverted by the driver by: + + input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC; + input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC; + +absmin & absmax are also used to scale the data, sine it is rather high +resolution. + + ---------------touch screen area----------------- + I MicroTouch (xmax,ymax) @I + I X I + I ########visible monitor area############## I + I #@ (xmin,ymin) # I + I # # I + I # # I + I # # I + I # # I + I # # I + I Y # # I + I # # I + I # # I + I # # I + I # # I + I # # I + I # (xmax,ymax) @# I + I ########################################## I + I I + I@ MicroTouch (xmin,ymin) I + ------------------------------------------------- + +Currently there is no way to calibrate the device via this driver. Perhaps +at some point an abstract function will be placed into evdev so generic +functions like calibrations, resets, and vendor information can be requested +(And the drivers would handle the vendor specific tasks). + +ADDITIONAL INFORMATION/UPDATES: + +http://groomlakelabs.com/grandamp/code/microtouch/ + +TODO: + +Implement a control urb again to handle requests to and from the device +such as calibration, etc. + +DISCLAMER: + +I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support +this driver! If you want touch drivers only supported within X, please go to: + +http://www.3m.com/3MTouchSystems/downloads/ + diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index e3866bac3494..6d752ba65860 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_AIPTEK) += input/ obj-$(CONFIG_USB_HID) += input/ obj-$(CONFIG_USB_KBD) += input/ obj-$(CONFIG_USB_MOUSE) += input/ +obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_DABUSB) += media/ diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index d8cef28b1dcd..7de24cb82b33 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -179,6 +179,18 @@ config USB_POWERMATE To compile this driver as a module, choose M here: the module will be called powermate. +config USB_MTOUCH + tristate "MicroTouch USB Touchscreen Driver" + depends on USB && INPUT + ---help--- + Say Y here if you want to use a MicroTouch (Now 3M) USB + Touchscreen controller. + + See for additional information. + + To compile this driver as a module, choose M here: the + module will be called mtouchusb. + config USB_XPAD tristate "X-Box gamepad support" depends on USB && INPUT diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 864922b04619..6f62fd3faf29 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -33,5 +33,6 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_POWERMATE) += powermate.o +obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c new file mode 100644 index 000000000000..42a4dceadb20 --- /dev/null +++ b/drivers/usb/input/mtouchusb.c @@ -0,0 +1,391 @@ +/****************************************************************************** + * mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens + * + * 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl) + * (http://freshmeat.net/projects/3mtouchscreendriver) + * + * History + * + * 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com + * Updated to 2.4.18, then 2.4.19 + * Old version still relied on stealing a minor + * + * 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com + * Complete rewrite using Linux Input in 2.6.3 + * Unfortunately no calibration support at this time + * + *****************************************************************************/ + +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include + +#define MTOUCHUSB_MIN_XC 0xc8 +#define MTOUCHUSB_MAX_XC 0xff78 +#define MTOUCHUSB_XC_FUZZ 0x0 +#define MTOUCHUSB_XC_FLAT 0x0 +#define MTOUCHUSB_MIN_YC 0x0 +#define MTOUCHUSB_MAX_YC 0xff78 +#define MTOUCHUSB_YC_FUZZ 0x0 +#define MTOUCHUSB_YC_FLAT 0x0 +#define MTOUCHUSB_ASYC_REPORT 1 +#define MTOUCHUSB_REPORT_SIZE_DATA 11 +#define MTOUCHUSB_REQ_CTRLLR_ID 10 + +#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3]) +#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5]) +#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0) + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com" +#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver" + +struct mtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + struct urb *irq; + struct usb_device *udev; + struct input_dev input; + int open; + char name[128]; + char phys[64]; +}; + +static __s32 vendor=-1, product=-1; + +static struct usb_device_id mtouchusb_devices [] = { + { USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */ + { } /* Terminating entry */ +}; + +static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) +{ + struct mtouch_usb *mtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_regs(&mtouch->input, regs); + input_report_key(&mtouch->input, BTN_TOUCH, + MTOUCHUSB_GET_TOUCHED(mtouch->data)); + input_report_abs(&mtouch->input, ABS_X, + MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(&mtouch->input, ABS_Y, + MTOUCHUSB_GET_YC(mtouch->data)); + input_sync(&mtouch->input); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int mtouchusb_open (struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + if (mtouch->open++) + return 0; + + mtouch->irq->dev = mtouch->udev; + + if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) + return -EIO; + + return 0; +} + +static void mtouchusb_close (struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + if (!--mtouch->open) + usb_unlink_urb (mtouch->irq); +} + +static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA, + SLAB_ATOMIC, &mtouch->data_dma); + + if (!mtouch->data) + return -1; + + return 0; +} + +static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + if (mtouch->data) + usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA, + mtouch->data, mtouch->data_dma); +} + +static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + dbg("%s - called", __FUNCTION__); + struct mtouch_usb *mtouch; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev (intf); + char path[64]; + char *buf; + int nRet; + int ix; + char valid_device = 0; + + if (vendor != -1 && product != -1) { + info("%s - User specified USB Touch -- Vend:Prod - %x:%x", + __FUNCTION__, vendor, product); + } + + for (ix = 0; ix < sizeof (mtouchusb_devices) / + sizeof (struct usb_device_id); ix++) { + if ((udev->descriptor.idVendor == + mtouchusb_devices [ix].idVendor) && + (udev->descriptor.idProduct == + mtouchusb_devices [ix].idProduct)) { + valid_device = 1; + break; + } + } + + if (udev->descriptor.idVendor == vendor && + udev->descriptor.idProduct == product) { /* User specified */ + valid_device = 1; + } + + if (!valid_device) { + err("%s - No valid device!", __FUNCTION__); + return -EIO; + } + + if (udev->descriptor.bNumConfigurations != 1) { + err("%s - Only one device configuration is supported.", + __FUNCTION__); + return -EIO; + } + + dbg("%s - setting interface", __FUNCTION__); + interface = &intf->altsetting[intf->act_altsetting]; + + dbg("%s - setting endpoint", __FUNCTION__); + endpoint = &interface->endpoint[0].desc; + + if (interface->desc.bNumEndpoints != 1) { + err("%s - Only one endpoint is supported.", __FUNCTION__); + return -EIO; + } + + if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { + err("%s - Out of memory.", __FUNCTION__); + return -ENOMEM; + } + + memset(mtouch, 0, sizeof(struct mtouch_usb)); + mtouch->udev = udev; + + dbg("%s - allocating buffers", __FUNCTION__); + if (mtouchusb_alloc_buffers(udev, mtouch)) { + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + mtouch->input.private = mtouch; + mtouch->input.open = mtouchusb_open; + mtouch->input.close = mtouchusb_close; + + usb_make_path(udev, path, 64); + sprintf(mtouch->phys, "%s/input0", path); + + mtouch->input.name = mtouch->name; + mtouch->input.phys = mtouch->phys; + mtouch->input.id.bustype = BUS_USB; + mtouch->input.id.vendor = udev->descriptor.idVendor; + mtouch->input.id.product = udev->descriptor.idProduct; + mtouch->input.id.version = udev->descriptor.bcdDevice; + mtouch->input.dev = &intf->dev; + + mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + /* Used to Scale Compensated Data and Flip Y */ + mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; + mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC; + mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; + mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; + mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC; + mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC; + mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; + mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + kfree(mtouch); + return -ENOMEM; + } + + if (udev->descriptor.iManufacturer && + usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(mtouch->name, buf); + if (udev->descriptor.iProduct && + usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0) + sprintf(mtouch->name, "%s %s", mtouch->name, buf); + + if (!strlen(mtouch->name)) + sprintf(mtouch->name, "USB Touchscreen %04x:%04x", + mtouch->input.id.vendor, mtouch->input.id.product); + + kfree(buf); + + nRet = usb_control_msg(mtouch->udev, + usb_rcvctrlpipe(udev, 0x80), + USB_REQ_GET_CONFIGURATION, + USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0, + 0x81, + NULL, + 0, + HZ * USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d", + __FUNCTION__, nRet); + + dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); + mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!mtouch->irq) { + dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + dbg("%s - usb_fill_int_urb", __FUNCTION__); + usb_fill_int_urb(mtouch->irq, + mtouch->udev, + usb_rcvintpipe(mtouch->udev, 0x81), + mtouch->data, + MTOUCHUSB_REPORT_SIZE_DATA, + mtouchusb_irq, + mtouch, + endpoint->bInterval); + + dbg("%s - input_register_device", __FUNCTION__); + input_register_device(&mtouch->input); + + nRet = usb_control_msg(mtouch->udev, + usb_rcvctrlpipe(udev, 0x80), + MTOUCHUSB_ASYC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MTOUCHUSB_ASYC_REPORT, + MTOUCHUSB_ASYC_REPORT, + NULL, + 0, + HZ * USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d", + __FUNCTION__, nRet); + + printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); + usb_set_intfdata(intf, mtouch); + + return 0; +} + +static void mtouchusb_disconnect(struct usb_interface *intf) +{ + struct mtouch_usb *mtouch = usb_get_intfdata (intf); + + dbg("%s - called", __FUNCTION__); + usb_set_intfdata(intf, NULL); + if (mtouch) { + dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); + usb_unlink_urb(mtouch->irq); + input_unregister_device(&mtouch->input); + usb_free_urb(mtouch->irq); + mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); + kfree(mtouch); + } +} + +MODULE_DEVICE_TABLE (usb, mtouchusb_devices); + +static struct usb_driver mtouchusb_driver = { + .owner = THIS_MODULE, + .name = "mtouchusb", + .probe = mtouchusb_probe, + .disconnect = mtouchusb_disconnect, + .id_table = mtouchusb_devices, +}; + +static int __init mtouchusb_init(void) { + dbg("%s - called", __FUNCTION__); + return usb_register(&mtouchusb_driver); +} + +static void __exit mtouchusb_cleanup(void) { + dbg("%s - called", __FUNCTION__); + usb_deregister(&mtouchusb_driver); +} + +module_init(mtouchusb_init); +module_exit(mtouchusb_cleanup); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); +MODULE_PARM(vendor, "i"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); +MODULE_PARM(product, "i"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); + + -- cgit v1.2.3 From 26a813163e0929592e7c415914bc220b9b1c9154 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Feb 2004 20:53:36 -0800 Subject: [PATCH] USB: fix build for older versions of gcc and the mtouchusb driver. --- drivers/usb/input/mtouchusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index 42a4dceadb20..f0733bebc263 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -173,7 +173,6 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - dbg("%s - called", __FUNCTION__); struct mtouch_usb *mtouch; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; @@ -184,6 +183,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i int ix; char valid_device = 0; + dbg("%s - called", __FUNCTION__); if (vendor != -1 && product != -1) { info("%s - User specified USB Touch -- Vend:Prod - %x:%x", __FUNCTION__, vendor, product); -- cgit v1.2.3 From 0ff9461051642a95e94f03561ba3d37e5db24290 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Feb 2004 20:53:52 -0800 Subject: [PATCH] USB: fix up the input Makefile after these last few drivers were added. --- drivers/usb/Makefile | 4 ++++ drivers/usb/input/Makefile | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 6d752ba65860..6e3a98f12605 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -20,11 +20,15 @@ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ obj-$(CONFIG_USB_AIPTEK) += input/ +obj-$(CONFIG_USB_ATI_REMOTE) += input/ obj-$(CONFIG_USB_HID) += input/ obj-$(CONFIG_USB_KBD) += input/ +obj-$(CONFIG_USB_KBTAB) += input/ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ +obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_WACOM) += input/ +obj-$(CONFIG_USB_XPAD) += input/ obj-$(CONFIG_USB_DABUSB) += media/ obj-$(CONFIG_USB_DSBR) += media/ diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 6f62fd3faf29..64fd3bed67bf 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -27,12 +27,12 @@ ifeq ($(CONFIG_HID_FF),y) endif obj-$(CONFIG_USB_AIPTEK) += aiptek.o +obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += hid.o obj-$(CONFIG_USB_KBD) += usbkbd.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o -obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_KBTAB) += kbtab.o -obj-$(CONFIG_USB_POWERMATE) += powermate.o +obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o +obj-$(CONFIG_USB_POWERMATE) += powermate.o +obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_XPAD) += xpad.o -obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o -- cgit v1.2.3 From 46d520a440d3670a0ae72c4e180d796028c9976b Mon Sep 17 00:00:00 2001 From: Torrey Hoffman Date: Fri, 27 Feb 2004 01:36:56 -0800 Subject: [PATCH] USB: update driver for ATI USB/RF remotes --- drivers/usb/input/ati_remote.c | 143 +++++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 63 deletions(-) diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index e62b6f9bfc43..163309400e67 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -93,27 +93,24 @@ #define DRIVER_VERSION "2.2.0" #define DRIVER_AUTHOR "Torrey Hoffman " -#define DRIVER_DESC "USB driver for ATI/X10 RF Remote Control" +#define DRIVER_DESC "ATI/X10 RF USB Remote Control" #define NAME_BUFSIZE 80 /* size of product name, path buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */ #define ATI_INPUTNUM 1 /* Which input device to register as */ -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif -module_param(debug, int, 444); -MODULE_PARM_DESC(debug, "Enable / disable debug messages"); - unsigned long channel_mask = 0; module_param(channel_mask, ulong, 444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) +int debug = 0; +module_param(debug, int, 444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) +#undef err +#define err(format, arg...) printk(KERN_ERR format , ## arg) + static struct usb_device_id ati_remote_table[] = { { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, {} /* Terminating entry */ @@ -132,6 +129,16 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table); static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; +/* Acceleration curve for directional control pad */ +static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; + +/* Duplicate event filtering time. + * Sequential, identical KIND_FILTERED inputs with less than + * FILTER_TIME jiffies between them are dropped. + * (HZ >> 4) == 1/16th of a second and works well for me. + */ +#define FILTER_TIME (HZ >> 4) + struct ati_remote { struct input_dev idev; struct usb_device *udev; @@ -279,12 +286,12 @@ static struct usb_driver ati_remote_driver = { static void ati_remote_dump(unsigned char *data, unsigned int len) { if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - warn("Weird byte 0x%02x", data[0]); + warn("Weird byte 0x%02x\n", data[0]); else if (len == 4) - warn("Weird key %02x %02x %02x %02x", + warn("Weird key %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]); else - warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", + warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", len, data[0], data[1], data[2], data[3], data[4], data[5]); } @@ -301,7 +308,8 @@ static int ati_remote_open(struct input_dev *inputdev) /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { - err(" %s: usb_submit_urb failed!", __FUNCTION__); + dev_err(&ati_remote->interface->dev, + "%s: usb_submit_urb failed!\n", __FUNCTION__); ati_remote->open--; return -EIO; } @@ -317,12 +325,12 @@ static void ati_remote_close(struct input_dev *inputdev) struct ati_remote *ati_remote = inputdev->private; if (ati_remote == NULL) { - dbg("%s - object is NULL !", __FUNCTION__); + err("ati_remote: %s: object is NULL!\n", __FUNCTION__); return; } if (ati_remote->open <= 0) - dbg("%s - ati_remote not open.", __FUNCTION__); + dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__); else --ati_remote->open; @@ -339,7 +347,8 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) struct ati_remote *ati_remote = urb->context; if (urb->status) { - warn("output urb completion status %d received", urb->status); + dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", + __FUNCTION__, urb->status); return; } @@ -375,7 +384,8 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne if (retval) { set_current_state(TASK_RUNNING); remove_wait_queue(&ati_remote->wait, &wait); - dbg("sendpacket: usb_submit_urb failed: %d", retval); + dev_dbg(&ati_remote->interface->dev, + "sendpacket: usb_submit_urb failed: %d\n", retval); return retval; } @@ -432,21 +442,26 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) } /* Mask unwanted remote channels. */ - /* note: remote_num is 0-based, channel 1 selected on remote == 0 here */ + /* note: remote_num is 0-based, channel 1 on remote == 0 here */ remote_num = (data[3] >> 4) & 0x0f; - if (channel_mask & (1 << (remote_num + 1))) { - dbg("Remote 0x02%x masked. mask = 0x%02lx", - remote_num, channel_mask); + if (channel_mask & (1 << (remote_num + 1))) { + dbginfo(&ati_remote->interface->dev, + "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", + remote_num, data[1], data[2], channel_mask); return; } - dbg("Remote channel 0x%02x: %02x%02x", remote_num, data[1], data[2]); /* Look up event code index in translation table */ index = ati_remote_event_lookup(remote_num, data[1], data[2]); if (index < 0) { - warn("Unknown key=%02x%02x", data[1], data[2]); + dev_warn(&ati_remote->interface->dev, + "Unknown input from channel 0x%02x: data %02x,%02x\n", + remote_num, data[1], data[2]); return; - } + } + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); if (ati_remote_tbl[index].kind == KIND_LITERAL) { input_regs(dev, regs); @@ -460,11 +475,10 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) } if (ati_remote_tbl[index].kind == KIND_FILTERED) { - /* Filter duplicate events which happen "too close" together, - * considered here to be anything less than a quarter second */ + /* Filter duplicate events which happen "too close" together. */ if ((ati_remote->old_data[0] == data[1]) && (ati_remote->old_data[1] == data[2]) && - ((ati_remote->old_jiffies + (HZ >> 2)) > jiffies)) { + ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) { ati_remote->old_jiffies = jiffies; return; } @@ -484,25 +498,25 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) /* * Other event kinds are from the directional control pad, and have an - * acceleration factor applied to them. Without added acceleration, the - * control pad is pretty unusable. + * acceleration factor applied to them. Without this acceleration, the + * control pad is mostly unusable. * * If elapsed time since last event is > 1/4 second, user "stopped", * so reset acceleration. Otherwise, user is probably holding the control * pad down, so we increase acceleration, ramping up over two seconds to - * a maximum speed. + * a maximum speed. The acceleration curve is #defined above. */ if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) { acc = 1; ati_remote->acc_jiffies = jiffies; } - else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = 1; - else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = 2; - else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = 3; - else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = 4; - else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = 6; - else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = 10; - else acc = 16; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = accel[0]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = accel[1]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = accel[2]; + else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = accel[3]; + else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = accel[4]; + else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = accel[5]; + else acc = accel[6]; input_regs(dev, regs); switch (ati_remote_tbl[index].kind) { @@ -528,7 +542,8 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) input_report_rel(dev, REL_Y, acc); break; default: - dbg("ati_remote kind=%d", ati_remote_tbl[index].kind); + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); } input_sync(dev); @@ -545,25 +560,25 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) struct ati_remote *ati_remote = urb->context; int retval; - switch (urb->status) - { + switch (urb->status) { case 0: /* success */ ati_remote_input_report(urb, regs); break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: - dbg("%s: urb error status (unlink?)", __FUNCTION__); + dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", + __FUNCTION__); return; default: /* error */ - dbg("%s: Nonzero urb status %d", __FUNCTION__, urb->status); + dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + __FUNCTION__, urb->status); } retval = usb_submit_urb(urb, SLAB_ATOMIC); if (retval) - err("%s: can't resubmit urb, %s-%s/input%d, status %d", - __FUNCTION__, ati_remote->udev->bus->bus_name, - ati_remote->udev->devpath, ATI_INPUTNUM, retval); + dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", + __FUNCTION__, retval); } /* @@ -654,7 +669,8 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) /* send initialization strings */ if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { - err("Initializing ati_remote hardware failed."); + dev_err(&ati_remote->interface->dev, + "Initializing ati_remote hardware failed.\n"); return 1; } @@ -686,34 +702,34 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de iface_host = &interface->altsetting[interface->act_altsetting]; if (iface_host->desc.bNumEndpoints != 2) { - dbg("Unexpected desc.bNumEndpoints."); + err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); retval = -ENODEV; goto error; } - + ati_remote->endpoint_in = &(iface_host->endpoint[0].desc); ati_remote->endpoint_out = &(iface_host->endpoint[1].desc); ati_remote->udev = udev; ati_remote->interface = interface; if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) { - dbg("Unexpected endpoint_in->bEndpointAddress."); + err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__); retval = -ENODEV; goto error; } if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) { - dbg("Unexpected endpoint_in->bmAttributes."); + err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__); retval = -ENODEV; goto error; } if (ati_remote->endpoint_in->wMaxPacketSize == 0) { - dbg("endpoint_in message size = 0?"); + err("%s: endpoint_in message size==0? \n", __FUNCTION__); retval = -ENODEV; goto error; } if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL))) goto error; - + /* Allocate URB buffers, URBs */ ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, &ati_remote->inbuf_dma); @@ -745,10 +761,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de sprintf(ati_remote->name, "%s %s", ati_remote->name, buf); if (!strlen(ati_remote->name)) - sprintf(ati_remote->name, "USB ATI (X10) remote %04x:%04x", - ati_remote->idev.id.vendor, ati_remote->idev.id.product); - - /* Device Hardware Initialization */ + sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", + ati_remote->udev->descriptor.idVendor, + ati_remote->udev->descriptor.idProduct); + + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ retval = ati_remote_initialize(ati_remote); if (retval) goto error; @@ -757,8 +774,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote_input_init(ati_remote); input_register_device(&ati_remote->idev); - info("Input registered: %s on %s", ati_remote->name, path); - info("USB (bus:dev)=(%d:%d)", udev->bus->busnum, udev->devnum); + dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", + ati_remote->name, path); usb_set_intfdata(interface, ati_remote); ati_remote->present = 1; @@ -783,7 +800,7 @@ static void ati_remote_disconnect(struct usb_interface *interface) ati_remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!ati_remote) { - warn("%s - null device?", __FUNCTION__); + warn("%s - null device?\n", __FUNCTION__); return; } @@ -806,9 +823,9 @@ static int __init ati_remote_init(void) result = usb_register(&ati_remote_driver); if (result) - err("usb_register error #%d", result); + err("usb_register error #%d\n", result); else - info("USB registered " DRIVER_DESC " ver. " DRIVER_VERSION); + info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION); return result; } -- cgit v1.2.3 From 0fec6053c4ba9796073c9927f1ba920ca0eb4e13 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 29 Feb 2004 18:38:34 -0800 Subject: [PATCH] USB ati_remote.c: don't be a namespace hog `debug', indeed. --- drivers/usb/input/ati_remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 163309400e67..28377a40142e 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -103,7 +103,7 @@ unsigned long channel_mask = 0; module_param(channel_mask, ulong, 444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); -int debug = 0; +static int debug = 0; module_param(debug, int, 444); MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); -- cgit v1.2.3 From 71d3b53362501a14482e1d7f871e99929d21f0c4 Mon Sep 17 00:00:00 2001 From: Art Haas Date: Sun, 29 Feb 2004 21:30:26 -0800 Subject: [PATCH] USB: C99 initializers for drivers/usb/serial/keyspan.h Here's a small patch changing the GNU-style initializers to C99 initializers. The patch is against the current BK. --- drivers/usb/serial/keyspan.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 9bb833b00462..e35371158914 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -359,19 +359,19 @@ static const struct keyspan_device_details usa19w_device_details = { }; static const struct keyspan_device_details usa19hs_device_details = { - product_id: keyspan_usa19hs_product_id, - msg_format: msg_usa90, - num_ports: 1, - indat_endp_flip: 0, - outdat_endp_flip: 0, - indat_endpoints: {0x81}, - outdat_endpoints: {0x01}, - inack_endpoints: {-1}, - outcont_endpoints: {0x02}, - instat_endpoint: 0x82, - glocont_endpoint: -1, - calculate_baud_rate: keyspan_usa19hs_calc_baud, - baudclk: KEYSPAN_USA19HS_BAUDCLK, + .product_id = keyspan_usa19hs_product_id, + .msg_format = msg_usa90, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {-1}, + .outcont_endpoints = {0x02}, + .instat_endpoint = 0x82, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa19hs_calc_baud, + .baudclk = KEYSPAN_USA19HS_BAUDCLK, }; static const struct keyspan_device_details usa28_device_details = { -- cgit v1.2.3 From ebe947c3570a916a91178d62cec8866b1ef84407 Mon Sep 17 00:00:00 2001 From: Per Winkvist Date: Sun, 29 Feb 2004 21:41:08 -0800 Subject: [PATCH] USB Storage: unusual devs fix for Pentax cameras. Please apply the attached patches instead. People have tried it on several different Pentax cameras (including 330 GS) --- drivers/usb/storage/unusual_devs.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 219bdb8028b9..bcd8e3429fcf 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -693,15 +693,9 @@ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* This entry from in the Debian mailing list */ -UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff, - "Pentax", - "Optio 330GS", - US_SC_8070, US_PR_CB, NULL, - US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ), /* Submitted by Per Winkvist */ -UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, +UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, "Pentax", "Optio S/S4", US_SC_DEVICE, US_PR_DEVICE, NULL, -- cgit v1.2.3 From 6779df3d28b3c9af1b14a5a3a29c125bed5a27ef Mon Sep 17 00:00:00 2001 From: Björn Brill Date: Sun, 29 Feb 2004 21:55:09 -0800 Subject: [PATCH] USB Storage: unusual_devs.h entry submission here is an unusual_devs.h entry which makes two different USB MP3 players work with Linux' USB storage driver. They share a core chip, the t33520 USB flash card controller by Trumpion microelectronics. They also share the same ID 0x090a:0x1001, which is a "generic" ID for t33520 devices using bulk-only protocol (0x1002 is for CB). About the MP3 players: - I own an apparently unbranded one (sold in masses on ebay.de) which needs US_FL_MODE_XLATE (and used to need US_FL_START_STOP before its removal). - Theodore Kilgore (who created the 0x090a:0x1001 record in the Linux-USB device overwiew) has a "Trumpion Digital Research MYMP3" which needs US_FL_MODE_XLATE and an explicit US_PR_BULK. Of course the different players report the same firmware rev. 1.00, despite their obviously different behaviour. Ugh. There are more players with this ID, the "Kaser Yofun 100 MP-3" (also rev. 1.00) being one. The proposed entry may or may not help them, but it shouldn't break working ones in any case. It is not unlikely they too will need US_FL_MODE_XLATE. Below you'll find my /proc/bus/usb/devices with mounted MP3 player and a patch against 2.4.25-rc3. Please apply. ----------------8<-------------------------8<-------------------- T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0 D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=0000 ProdID=0000 Rev= 0.00 S: Product=USB UHCI Root Hub S: SerialNumber=e400 C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=090a ProdID=1001 Rev= 1.00 C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr= 60mA I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=255ms ----------------8<-------------------------8<-------------------- --- drivers/usb/storage/unusual_devs.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index bcd8e3429fcf..00ae8b1a9ebd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -654,6 +654,17 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), +/* Entry needed for flags. Moreover, all devices with this ID use + * bulk-only transport, but _some_ falsely report Control/Bulk instead. + * One example is "Trumpion Digital Research MYMP3". + * Submitted by Bjoern Brill + */ +UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, + "Trumpion", + "t33520 USB Flash Card Controller", + US_SC_DEVICE, US_PR_BULK, NULL, + US_FL_MODE_XLATE), + /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, "Trumpion", -- cgit v1.2.3 From 794e227d10f15de0d0f787a6db0c5df6a4cd28a9 Mon Sep 17 00:00:00 2001 From: Jürgen Botz Date: Sun, 29 Feb 2004 23:04:41 -0800 Subject: [PATCH] USB: visor patch for Samsung SPH-i500 Hi... here is a patch for the vendor/device codes for the Samsung SPH-i500 Palm phone. --- drivers/usb/serial/visor.c | 3 +++ drivers/usb/serial/visor.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index f48d6ae4485c..b00375d4dc14 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -239,6 +239,8 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), + .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID), @@ -275,6 +277,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { }, /* optional parameter entry */ diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 80d55d8474b5..e586a6d97960 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -46,6 +46,7 @@ #define SAMSUNG_VENDOR_ID 0x04E8 #define SAMSUNG_SCH_I330_ID 0x8001 +#define SAMSUNG_SPH_I500_ID 0x6601 #define GARMIN_VENDOR_ID 0x091E #define GARMIN_IQUE_3600_ID 0x0004 -- cgit v1.2.3 From 35ca8838e4117cba1866f9ceebb14167871d089c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 29 Feb 2004 23:58:31 -0800 Subject: [PATCH] USB Storage: Revision of as202, Genesys quirk patch In the slave_configure routine it's already too late for the host's max_sector value to affect the scsi_device. It's necessary to set the queue value directly. This revised patch takes care of that. --- drivers/usb/storage/scsiglue.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 6f1ea41d83a8..30e1d89922dc 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -64,8 +64,10 @@ static const char* host_info(struct Scsi_Host *host) return "SCSI emulation for USB Mass Storage devices"; } -static int slave_configure (struct scsi_device *sdev) +static int slave_configure(struct scsi_device *sdev) { + struct us_data *us = (struct us_data *) sdev->host->hostdata[0]; + /* Scatter-gather buffers (all but the last) must have a length * divisible by the bulk maxpacket size. Otherwise a data packet * would end up being short, causing a premature end to the data @@ -76,6 +78,16 @@ static int slave_configure (struct scsi_device *sdev) * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); + /* Devices using Genesys Logic chips cause a lot of trouble for + * high-speed transfers; they die unpredictably when given more + * than 64 KB of data at a time. If we detect such a device, + * reduce the maximum transfer size to 64 KB = 128 sectors. */ + +#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location + if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS && + us->pusb_dev->speed == USB_SPEED_HIGH) + blk_queue_max_sectors(sdev->request_queue, 128); + /* this is to satisify the compiler, tho I don't think the * return code is ever checked anywhere. */ return 0; -- cgit v1.2.3 From f285ff9b83f4b75bfe6b6c9920913a0d9c9c95ba Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 2 Mar 2004 18:00:13 -0800 Subject: [PATCH] USB Gadget: make usb gadget strings talk utf-8 Teach gadget/usbstring to expect UTF-8 strings, not ISO-8859/1 ones. This just gets rid of an API issue: no hacks needed for non-Western languages, and multi-language support will be lots easier. Current drivers won't notice the API change, they use US-ASCII (which is a strict superset of both encodings). Future drivers may want to teach utf8_to_utf16le() about the four-byte encodings, so they can emit surrogate pairs for those Unicode characters. --- drivers/usb/gadget/usbstring.c | 92 +++++++++++++++++++++++++++++++++++------- include/linux/usb_gadget.h | 2 +- 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 8ccb62ef1cf8..f5fcd1edaf07 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -16,24 +16,89 @@ #include #include +#include + + +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len) +{ + int count = 0; + u8 c; + u16 uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u8) *s++) != 0) { + if (unlikely(c & 0x80)) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + put_unaligned (cpu_to_le16 (uchar), cp++); + count++; + len--; + } + return count; +fail: + return -1; +} + /** * usb_gadget_get_string - fill out a string descriptor - * @table: of c strings using iso latin/1 characters + * @table: of c strings encoded using UTF-8 * @id: string id, from low byte of wValue in get string descriptor * @buf: at least 256 bytes * - * Finds the iso latin/1 string matching the ID, and converts it into a + * Finds the UTF-8 string matching the ID, and converts it into a * string descriptor in utf16-le. * Returns length of descriptor (always even) or negative errno * - * If your driver needs stings in multiple languages, you'll need to - * to use some alternate solution for languages where the ISO 8859/1 - * (latin/1) character set can't be used. For example, they can't be - * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other - * languages. You'd likely "switch (wIndex) { ... }" in your ep0 - * string descriptor logic, using this routine in cases where "western - * european" characters suffice for the strings being returned. + * If your driver needs stings in multiple languages, you'll probably + * "switch (wIndex) { ... }" in your ep0 string descriptor logic, + * using this routine after choosing which set of UTF-8 strings to use. + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 + * characters (which are also widely used in C strings). */ int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) @@ -59,13 +124,12 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) /* string descriptors have length, tag, then UTF16-LE text */ len = min ((size_t) 126, strlen (s->s)); + memset (buf + 2, 0, 2 * len); /* zero all the bytes */ + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len); + if (len < 0) + return -EINVAL; buf [0] = (len + 1) * 2; buf [1] = USB_DT_STRING; - memset (buf + 2, 0, 2 * len); /* zero all the high bytes */ - while (len) { - buf [2 * len] = s->s [len - 1]; - len--; - } return buf [0]; } diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 78c8382b6398..041e2540a48e 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -690,7 +690,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); /** * struct usb_string - wraps a C string and its USB id * @id:the (nonzero) ID for this string - * @s:the string, in ISO-8859/1 characters + * @s:the string, in UTF-8 encoding * * If you're using usb_gadget_get_string(), use this to wrap a string * together with its ID. -- cgit v1.2.3 From 4ccbe94c79c9d9981896159b0119466275a17ff1 Mon Sep 17 00:00:00 2001 From: Thomas Sailer Date: Tue, 2 Mar 2004 18:16:35 -0800 Subject: [PATCH] USB: USB OSS audio driver workaround for buggy descriptors --- drivers/usb/class/audio.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c index 37f6070e6936..ef136e105526 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -3,7 +3,7 @@ /* * audio.c -- USB Audio Class driver * - * Copyright (C) 1999, 2000, 2001 + * Copyright (C) 1999, 2000, 2001, 2003, 2004 * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -101,6 +101,8 @@ * Fix SNDCTL_DSP_STEREO API violation * 2003-04-08: Oliver Neukum (oliver@neukum.name): * Setting a configuration is done by usbcore and must not be overridden + * 2004-02-27: Workaround for broken synch descriptors + * */ /* @@ -1542,12 +1544,13 @@ static int set_format_in(struct usb_audiodev *as) alts->endpoint[1].desc.bmAttributes != 0x01 || alts->endpoint[1].desc.bSynchAddress != 0 || alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in " + "but has invalid synch pipe; treating as asynchronous in\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].desc.bRefresh; } - u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; @@ -1637,12 +1640,13 @@ static int set_format_out(struct usb_audiodev *as) alts->endpoint[1].desc.bmAttributes != 0x01 || alts->endpoint[1].desc.bSynchAddress != 0 || alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out " + "but has invalid synch pipe; treating as adaptive out\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].desc.bRefresh; } - u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; -- cgit v1.2.3 From aa36bfd289a4e18f6c369e433af013f6598b39ef Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 19:16:57 -0800 Subject: [PATCH] USB: Don't add/del interfaces, register/unregister them On Fri, 27 Feb 2004, Greg KH wrote: > On Wed, Feb 25, 2004 at 10:05:37AM -0500, Alan Stern wrote: > > > Why would anyone want to do this, you ask? Well the USB subsystem does it > > already. Each USB device can have several configurations, only one of > > which is active at any time. Corresponding to each configuration is a set > > of struct devices, and they (together with their embedded kobjects) are > > allocated and initialized when the USB device is first detected. The > > struct devices are add()'ed and del()'ed as configurations are activated > > and deactivated, leading to just the sort of call sequence shown above. > > Then we need to fix this. The driver model does not support repeated device_add(), device_del(), device_add(), device_del(), ... calls for the same device. But that's what happens to an interface's embedded struct device when we change configurations. Accordingly, this patch changes the device_add()/device_del() calls for interfaces to device_register()/device_unregister(). When the interface is unregistered the new code waits for the release method to run, so that it will be safe to re-register the interface should the former configuration be reinstated. Greg, please check this out to make sure I haven't made some dumb mistake. It works on my system and it fixes a memory leak in the USB system. --- drivers/usb/core/config.c | 9 ++------- drivers/usb/core/message.c | 16 ++++++++++++++-- include/linux/usb.h | 3 +++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 2332526cd803..bab2ef11a7d8 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -72,13 +72,10 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char return buffer - buffer0; } -static void usb_release_intf(struct device *dev) +static void usb_free_intf(struct usb_interface *intf) { - struct usb_interface *intf; int j; - intf = to_usb_interface(dev); - if (intf->altsetting) { for (j = 0; j < intf->num_altsetting; j++) { struct usb_host_interface *as = &intf->altsetting[j]; @@ -235,8 +232,6 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer, int si return -ENOMEM; } memset(interface, 0, sizeof(struct usb_interface)); - interface->dev.release = usb_release_intf; - device_initialize(&interface->dev); } /* Go through the descriptors, checking their length and counting the @@ -374,7 +369,7 @@ void usb_destroy_configuration(struct usb_device *dev) struct usb_interface *ifp = cf->interface[i]; if (ifp) - put_device(&ifp->dev); + usb_free_intf(ifp); } } kfree(dev->config); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 08a1e38e72e9..87924db94039 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -793,6 +793,13 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) } } +static void release_interface(struct device *dev) +{ + struct usb_interface *interface = to_usb_interface(dev); + + complete(interface->released); +} + /* * usb_disable_device - Disable all the endpoints for a USB device * @dev: the device whose endpoints are being disabled @@ -822,12 +829,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) if (dev->actconfig) { for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *interface; + struct completion intf_completion; /* remove this interface */ interface = dev->actconfig->interface[i]; dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); - device_del(&interface->dev); + init_completion (&intf_completion); + interface->released = &intf_completion; + device_unregister (&interface->dev); + wait_for_completion (&intf_completion); } dev->actconfig = 0; if (dev->state == USB_STATE_CONFIGURED) @@ -1145,6 +1156,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; intf->dev.dma_mask = dev->dev.dma_mask; + intf->dev.release = release_interface; sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, @@ -1153,7 +1165,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) "registering %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, desc->bInterfaceNumber); - device_add (&intf->dev); + device_register (&intf->dev); usb_create_driverfs_intf_files (intf); } } diff --git a/include/linux/usb.h b/include/linux/usb.h index 45caca344ca3..6a2e0b7f18d8 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -89,6 +89,8 @@ struct usb_host_interface { * number from the USB core by calling usb_register_dev(). * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. + * @released: wait for the interface to be released when changing + * configurations. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -122,6 +124,7 @@ struct usb_interface { int minor; /* minor number this interface is bound to */ struct device dev; /* interface specific device info */ struct class_device *class_dev; + struct completion *released; /* wait for release */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ -- cgit v1.2.3 From e8a19690d7b04fde093d7d1d62b2e1f1b1b4db98 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 20:49:44 -0800 Subject: [PATCH] USB: Improve handling of altsettings On Sat, 21 Feb 2004, Greg KH wrote: > > One thing that would be good, whether this change gets made or not, is to > > remove all assumptions from drivers about the order in which interfaces > > are stored (use usb_ifnum_to_if()) and the order in which altsettings are > > stored (replace intf.act_altsetting with a pointer and create > > usb_altnum_to_alt() analogous to usb_ifnum_to_if()). There are plenty of > > drivers that will need to be fixed up. > > I'd be glad to take patches to fix up any drivers that still have this > problem right now. Here's a start. This patch begins the conversion process by adding usbcore support for cur_altsetting and deprecating act_altsetting. So long as we assumed that altsetting numbers range from 0 to num_altsetting-1 and that the number matches its index in the altsetting array, there was no harm in using act_altsetting. But without that assumption act_altsetting is merely an invitation to errors. Although the kerneldoc says that act_altsetting is the _index_ of the active altsetting, it's all too easy to confuse it with the _number_ of the active altsetting. Using cur_altsetting instead (a pointer rather than a number) will prevent that confusion. Until all the drivers have been converted to use cur_altsetting, the core will have to maintain act_altsetting in parallel with it. Eventually we will be able to remove act_altsetting, but fixing all the drivers will take a while. Included in this patch: Add cur_altsetting to struct usb_interface and deprecate act_altsetting. Add comments and kerneldoc explaining the changes. Also remove the comments in front of struct usb_host_config (they seem to have been left behind when usb_ch9.h was split out) and add kerneldoc for that structure. Add usb_altnum_to_altsetting() to help look up altsettings based on their number. Convert the usb_set_interface(), usb_set_configuration(), and usb_reset_configuration() routines to support cur_altsetting and act_altsetting in parallel. Convert a few others to use cur_altsetting rather than act_altsetting. Rename a few local variables to make their meaning a little clearer. It would be nice to change struct usb_host_interface to something like usb_host_altsetting, but that's a patch for another time. --- drivers/usb/core/message.c | 68 ++++++++++++++++++++++++++--------------- drivers/usb/core/usb.c | 42 ++++++++++++++++++++----- include/linux/usb.h | 76 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 135 insertions(+), 51 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 87924db94039..76226e37bb36 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -783,13 +783,12 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) */ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) { - struct usb_host_interface *hintf = - &intf->altsetting[intf->act_altsetting]; + struct usb_host_interface *alt = intf->cur_altsetting; int i; - for (i = 0; i < hintf->desc.bNumEndpoints; ++i) { + for (i = 0; i < alt->desc.bNumEndpoints; ++i) { usb_disable_endpoint(dev, - hintf->endpoint[i].desc.bEndpointAddress); + alt->endpoint[i].desc.bEndpointAddress); } } @@ -887,12 +886,11 @@ void usb_enable_endpoint(struct usb_device *dev, void usb_enable_interface(struct usb_device *dev, struct usb_interface *intf) { - struct usb_host_interface *hintf = - &intf->altsetting[intf->act_altsetting]; + struct usb_host_interface *alt = intf->cur_altsetting; int i; - for (i = 0; i < hintf->desc.bNumEndpoints; ++i) - usb_enable_endpoint(dev, &hintf->endpoint[i].desc); + for (i = 0; i < alt->desc.bNumEndpoints; ++i) + usb_enable_endpoint(dev, &alt->endpoint[i].desc); } /** @@ -931,6 +929,7 @@ void usb_enable_interface(struct usb_device *dev, int usb_set_interface(struct usb_device *dev, int interface, int alternate) { struct usb_interface *iface; + struct usb_host_interface *alt; int ret; int manual = 0; @@ -940,14 +939,15 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return -EINVAL; } - if (alternate < 0 || alternate >= iface->num_altsetting) + alt = usb_altnum_to_altsetting(iface, alternate); + if (!alt) { + warn("selecting invalid altsetting %d", alternate); return -EINVAL; + } ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - iface->altsetting[alternate] - .desc.bAlternateSetting, - interface, NULL, 0, HZ * 5); + alternate, interface, NULL, 0, HZ * 5); /* 9.4.10 says devices don't need this and are free to STALL the * request if the interface only has one alternate setting. @@ -968,7 +968,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) /* prevent submissions using previous endpoint settings */ usb_disable_interface(dev, iface); - iface->act_altsetting = alternate; + iface->cur_altsetting = alt; + iface->act_altsetting = alt - iface->altsetting; /* If the interface only has one altsetting and the device didn't * accept the request, we attempt to carry out the equivalent action @@ -976,13 +977,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * new altsetting. */ if (manual) { - struct usb_host_interface *iface_as = - &iface->altsetting[alternate]; int i; - for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { + for (i = 0; i < alt->desc.bNumEndpoints; i++) { unsigned int epaddr = - iface_as->endpoint[i].desc.bEndpointAddress; + alt->endpoint[i].desc.bEndpointAddress; unsigned int pipe = __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr) | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN); @@ -1056,8 +1055,20 @@ int usb_reset_configuration(struct usb_device *dev) /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; + struct usb_host_interface *alt; + + alt = usb_altnum_to_altsetting(intf, 0); + + /* No altsetting 0? We'll assume the first altsetting. + * We could use a GetInterface call, but if a device is + * so non-compliant that it doesn't have altsetting 0 + * then I wouldn't trust its reply anyway. + */ + if (!alt) + alt = &intf->altsetting[0]; - intf->act_altsetting = 0; + intf->cur_altsetting = alt; + intf->act_altsetting = alt - intf->altsetting; usb_enable_interface(dev, intf); } return 0; @@ -1146,12 +1157,21 @@ int usb_set_configuration(struct usb_device *dev, int configuration) */ for (i = 0; i < cp->desc.bNumInterfaces; ++i) { struct usb_interface *intf = cp->interface[i]; - struct usb_interface_descriptor *desc; + struct usb_host_interface *alt; - intf->act_altsetting = 0; - desc = &intf->altsetting [0].desc; - usb_enable_interface(dev, intf); + alt = usb_altnum_to_altsetting(intf, 0); + + /* No altsetting 0? We'll assume the first altsetting. + * We could use a GetInterface call, but if a device is + * so non-compliant that it doesn't have altsetting 0 + * then I wouldn't trust its reply anyway. + */ + if (!alt) + alt = &intf->altsetting[0]; + intf->cur_altsetting = alt; + intf->act_altsetting = alt - intf->altsetting; + usb_enable_interface(dev, intf); intf->dev.parent = &dev->dev; intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; @@ -1160,11 +1180,11 @@ int usb_set_configuration(struct usb_device *dev, int configuration) sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, - desc->bInterfaceNumber); + alt->desc.bInterfaceNumber); dev_dbg (&dev->dev, "registering %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - desc->bInterfaceNumber); + alt->desc.bInterfaceNumber); device_register (&intf->dev); usb_create_driverfs_intf_files (intf); } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f2ecd4308e0c..2ccb746c1f7a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -189,7 +189,7 @@ void usb_deregister(struct usb_driver *driver) } /** - * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal) + * usb_ifnum_to_if - get the interface object with a given interface number * @dev: the device whose current configuration is considered * @ifnum: the desired interface * @@ -219,6 +219,33 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) return NULL; } +/** + * usb_altnum_to_altsetting - get the altsetting structure with a given + * alternate setting number. + * @intf: the interface containing the altsetting in question + * @altnum: the desired alternate setting number + * + * This searches the altsetting array of the specified interface for + * an entry with the correct bAlternateSetting value and returns a pointer + * to that entry, or null. + * + * Note that altsettings need not be stored sequentially by number, so + * it would be incorrect to assume that the first altsetting entry in + * the array corresponds to altsetting zero. This routine helps device + * drivers avoid such mistakes. + */ +struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, + unsigned int altnum) +{ + int i; + + for (i = 0; i < intf->num_altsetting; i++) { + if (intf->altsetting[i].desc.bAlternateSetting == altnum) + return &intf->altsetting[i]; + } + return NULL; +} + /** * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number * @dev: the device whose current configuration+altsettings is considered @@ -247,7 +274,7 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) /* only endpoints in current altsetting are active */ intf = config->interface[i]; - alt = intf->altsetting + intf->act_altsetting; + alt = intf->cur_altsetting; for (k = 0; k < alt->desc.bNumEndpoints; k++) if (epnum == alt->endpoint[k].desc.bEndpointAddress) @@ -421,7 +448,7 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) if (id == NULL) return NULL; - intf = &interface->altsetting [interface->act_altsetting]; + intf = interface->cur_altsetting; dev = interface_to_usbdev(interface); /* It is important to check that id->driver_info is nonzero, @@ -624,7 +651,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, scratch += length; if (usb_dev->descriptor.bDeviceClass == 0) { - int alt = intf->act_altsetting; + struct usb_host_interface *alt = intf->cur_altsetting; /* 2.4 only exposed interface zero. in 2.5, hotplug * agents are called for all interfaces, and can use @@ -633,9 +660,9 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, envp [i++] = scratch; length += snprintf (scratch, buffer_size - length, "INTERFACE=%d/%d/%d", - intf->altsetting[alt].desc.bInterfaceClass, - intf->altsetting[alt].desc.bInterfaceSubClass, - intf->altsetting[alt].desc.bInterfaceProtocol); + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol); if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; ++length; @@ -1582,6 +1609,7 @@ EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_find_interface); EXPORT_SYMBOL(usb_ifnum_to_if); +EXPORT_SYMBOL(usb_altnum_to_altsetting); EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_disconnect); diff --git a/include/linux/usb.h b/include/linux/usb.h index 6a2e0b7f18d8..e7e102afcb20 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -72,14 +72,15 @@ struct usb_host_interface { /** * struct usb_interface - what usb device drivers talk to - * @altsetting: array of interface descriptors, one for each alternate + * @altsetting: array of interface structures, one for each alternate * setting that may be selected. Each one includes a set of - * endpoint configurations and will be in numberic order, - * 0..num_altsetting. + * endpoint configurations. They will be in no particular order. * @num_altsetting: number of altsettings defined. - * @act_altsetting: index of current altsetting. this number is always - * less than num_altsetting. after the device is configured, each + * @cur_altsetting: the current altsetting. + * @act_altsetting: index of current altsetting. This number is always + * less than num_altsetting. After the device is configured, each * interface uses its default setting of zero. + * NOTE: act_altsetting is deprecated. Use cur_altsetting instead. * @driver: the USB driver that is bound to this interface. * @minor: the minor number assigned to this interface, if this * interface is bound to a driver that uses the USB major number. @@ -104,20 +105,27 @@ struct usb_host_interface { * calls such as dev_get_drvdata() on the dev member of this structure. * * Each interface may have alternate settings. The initial configuration - * of a device sets the first of these, but the device driver can change + * of a device sets altsetting 0, but the device driver can change * that setting using usb_set_interface(). Alternate settings are often * used to control the the use of periodic endpoints, such as by having * different endpoints use different amounts of reserved USB bandwidth. * All standards-conformant USB devices that use isochronous endpoints * will use them in non-default settings. + * + * The USB specification says that alternate setting numbers must run from + * 0 to one less than the total number of alternate settings. But some + * devices manage to mess this up, and the structures aren't necessarily + * stored in numerical order anyhow. Use usb_altnum_to_altsetting() to + * look up an alternate setting in the altsetting array based on its number. */ struct usb_interface { - /* array of alternate settings for this interface. - * these will be in numeric order, 0..num_altsettting - */ + /* array of alternate settings for this interface, + * stored in no particular order */ struct usb_host_interface *altsetting; - unsigned act_altsetting; /* active alternate setting */ + struct usb_host_interface *cur_altsetting; /* the currently + * active alternate setting */ + unsigned act_altsetting; /* index of active alternate setting: DEPRECATED */ unsigned num_altsetting; /* number of alternate settings */ struct usb_driver *driver; /* driver */ @@ -143,19 +151,43 @@ static inline void usb_set_intfdata (struct usb_interface *intf, void *data) /* this maximum is arbitrary */ #define USB_MAXINTERFACES 32 -/* USB_DT_CONFIG: Configuration descriptor information. +/** + * struct usb_host_config - representation of a device's configuration + * @desc: the device's configuration descriptor. + * @interface: array of usb_interface structures, one for each interface + * in the configuration. The number of interfaces is stored in + * desc.bNumInterfaces. + * @extra: pointer to buffer containing all extra descriptors associated + * with this configuration (those preceding the first interface + * descriptor). + * @extralen: length of the extra descriptors buffer. * - * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the - * descriptor type is different. Highspeed-capable devices can look - * different depending on what speed they're currently running. Only - * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG. + * USB devices may have multiple configurations, but only one can be active + * at any time. Each encapsulates a different operational environment; + * for example, a dual-speed device would have separate configurations for + * full-speed and high-speed operation. The number of configurations + * available is stored in the device descriptor as bNumConfigurations. + * + * A configuration can contain multiple interfaces. Each corresponds to + * a different function of the USB device, and all are available whenever + * the configuration is active. The USB standard says that interfaces + * are supposed to be numbered from 0 to desc.bNumInterfaces-1, but a lot + * of devices get this wrong. In addition, the interface array is not + * guaranteed to be sorted in numerical order. Use usb_ifnum_to_if() to + * look up an interface entry based on its number. + * + * Device drivers should not attempt to activate configurations. The choice + * of which configuration to install is a policy decision based on such + * considerations as available power, functionality provided, and the user's + * desires (expressed through hotplug scripts). However, drivers can call + * usb_reset_configuration() to reinitialize the current configuration and + * all its interfaces. */ struct usb_host_config { struct usb_config_descriptor desc; - /* the interfaces associated with this configuration - * these will be in numeric order, 0..desc.bNumInterfaces - */ + /* the interfaces associated with this configuration, + * stored in no particular order */ struct usb_interface *interface[USB_MAXINTERFACES]; unsigned char *extra; /* Extra descriptors */ @@ -297,8 +329,12 @@ extern void usb_driver_release_interface(struct usb_driver *driver, const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id); -extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); -extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); +extern struct usb_interface *usb_find_interface(struct usb_driver *drv, + int minor); +extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, + unsigned ifnum); +extern struct usb_host_interface *usb_altnum_to_altsetting( + struct usb_interface *intf, unsigned int altnum); /** -- cgit v1.2.3 From 3f48fc79af1b124acca11c856ca352a27835536e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 20:52:13 -0800 Subject: [PATCH] USB: Convert usbcore to use cur_altsetting This patch continues the work of as209 by converting the rest of usbcore to use cur_altsetting in place of act_altsetting. The changes required are fairly small, just in the sysfs attributes and hub configuration. --- drivers/usb/core/driverfs.c | 8 ++------ drivers/usb/core/hub.c | 12 ++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c index d45f39229897..ed14bb6987b9 100644 --- a/drivers/usb/core/driverfs.c +++ b/drivers/usb/core/driverfs.c @@ -166,13 +166,9 @@ void usb_create_driverfs_dev_files (struct usb_device *udev) static ssize_t \ show_##field (struct device *dev, char *buf) \ { \ - struct usb_interface *intf; \ - int alt; \ + struct usb_interface *intf = to_usb_interface (dev); \ \ - intf = to_usb_interface (dev); \ - alt = intf->act_altsetting; \ - \ - return sprintf (buf, format_string, intf->altsetting[alt].desc.field); \ + return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 39ec4bdf4fbe..d48cbc419117 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -560,7 +560,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_hub *hub; unsigned long flags; - desc = intf->altsetting + intf->act_altsetting; + desc = intf->cur_altsetting; dev = interface_to_usbdev(intf); /* Some hubs have a subclass of 1, which AFAICT according to the */ @@ -1344,15 +1344,15 @@ int usb_physical_reset_device(struct usb_device *dev) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *intf = dev->actconfig->interface[i]; - struct usb_interface_descriptor *as; + struct usb_interface_descriptor *desc; - as = &intf->altsetting[intf->act_altsetting].desc; - ret = usb_set_interface(dev, as->bInterfaceNumber, - as->bAlternateSetting); + desc = &intf->cur_altsetting->desc; + ret = usb_set_interface(dev, desc->bInterfaceNumber, + desc->bAlternateSetting); if (ret < 0) { err("failed to set active alternate setting " "for dev %s interface %d (error=%d)", - dev->devpath, i, ret); + dev->devpath, desc->bInterfaceNumber, ret); return ret; } } -- cgit v1.2.3 From b5ca4f612390dbe8a833a6ce85bd8fc9bb6e8ea0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 20:52:40 -0800 Subject: [PATCH] USB: Small improvements for devio.c devio.c doesn't need to be changed to support the new altsetting mechanism, but while looking through it I noticed a couple of places that could be improved slightly. Here they are, just removal of some redundant tests (all altsettings for the same interface are guaranteed to have the same bInterfaceNumber) and function calls. --- drivers/usb/core/devio.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 68ca2b2abfee..7fdd2df17a12 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -430,19 +430,14 @@ static int findintfep(struct usb_device *dev, unsigned int ep) static int findintfif(struct usb_device *dev, unsigned int ifn) { - unsigned int i, j; - struct usb_interface *iface; - struct usb_host_interface *alts; + unsigned int i; if (ifn & ~0xff) return -EINVAL; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - iface = dev->actconfig->interface[i]; - for (j = 0; j < iface->num_altsetting; j++) { - alts = &iface->altsetting[j]; - if (alts->desc.bInterfaceNumber == ifn) - return i; - } + if (dev->actconfig->interface[i]-> + altsetting[0].desc.bInterfaceNumber == ifn) + return i; } return -ENOENT; } @@ -688,9 +683,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) return -EFAULT; if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; - interface = usb_ifnum_to_if(ps->dev, gd.interface); - if (!interface) - return -EINVAL; + interface = ps->dev->actconfig->interface[ret]; if (!interface->driver) return -ENODATA; strcpy(gd.driver, interface->driver->name); @@ -744,9 +737,7 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) return -EFAULT; if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; - interface = usb_ifnum_to_if(ps->dev, setintf.interface); - if (!interface) - return -EINVAL; + interface = ps->dev->actconfig->interface[ret]; if (interface->driver) { if ((ret = checkintf(ps, ret))) return ret; -- cgit v1.2.3 From 9967693e40d26c989acfbea2a9404a91e4976131 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 20:53:03 -0800 Subject: [PATCH] USB: Convert usb-storage to use cur_altsetting I'm beginning the process of converting device drivers to use cur_altsetting with usb-storage, the one I know best. Only a few changes are needed (and the first one isn't even really necessary). --- drivers/usb/storage/usb.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5c78db52e806..ef04888ffd2d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -423,7 +423,7 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) /* Fill in the device-related fields */ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; - us->ifnum = intf->altsetting->desc.bInterfaceNumber; + us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; /* Store our private data in the interface and increment the * device's reference count */ @@ -452,7 +452,7 @@ static void get_device_info(struct us_data *us, int id_index) { struct usb_device *dev = us->pusb_dev; struct usb_interface_descriptor *idesc = - &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting].desc; + &us->pusb_intf->cur_altsetting->desc; struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; struct usb_device_id *id = &storage_usb_ids[id_index]; @@ -686,7 +686,7 @@ static int get_protocol(struct us_data *us) static int get_pipes(struct us_data *us) { struct usb_host_interface *altsetting = - &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting]; + us->pusb_intf->cur_altsetting; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; @@ -877,8 +877,9 @@ static int storage_probe(struct usb_interface *intf, int result; US_DEBUGP("USB Mass Storage device detected\n"); - US_DEBUGP("act_altsetting is %d, id_index is %d\n", - intf->act_altsetting, id_index); + US_DEBUGP("altsetting is %d, id_index is %d\n", + intf->cur_altsetting->desc.bAlternateSetting, + id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); -- cgit v1.2.3 From b2144480cff8e0f52dff9c3ca2dca138039b207d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Mar 2004 20:53:25 -0800 Subject: [PATCH] USB: Convert usbtest to the new altsetting regime This patch converts the usbtest driver to the new way altsettings work. The largest change is to remove the assumptions that altsetting numbers lie in the correct range (a debugging message is logged if they don't but execution doesn't stop) and that the array is sorted by number. --- drivers/usb/misc/usbtest.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 45c05e08fd9f..901cb178f231 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -490,7 +490,7 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate) struct usb_interface *iface = dev->intf; struct usb_device *udev; - if (alternate < 0 || alternate >= iface->num_altsetting) + if (alternate < 0 || alternate >= 256) return -EINVAL; udev = interface_to_usbdev (iface); @@ -556,23 +556,19 @@ static int ch9_postconfig (struct usbtest_dev *dev) { struct usb_interface *iface = dev->intf; struct usb_device *udev = interface_to_usbdev (iface); - int i, retval; + int i, alt, retval; /* [9.2.3] if there's more than one altsetting, we need to be able to * set and get each one. mostly trusts the descriptors from usbcore. */ for (i = 0; i < iface->num_altsetting; i++) { - /* 9.2.3 constrains the range here, and Linux ensures - * they're ordered meaningfully in this array - */ - if (iface->altsetting [i].desc.bAlternateSetting != i) { + /* 9.2.3 constrains the range here */ + alt = iface->altsetting [i].desc.bAlternateSetting; + if (alt < 0 || alt >= iface->num_altsetting) { dev_dbg (&iface->dev, "invalid alt [%d].bAltSetting = %d\n", - i, - iface->altsetting [i].desc - .bAlternateSetting); - return -EDOM; + i, alt); } /* [real world] get/set unimplemented if there's only one */ @@ -580,18 +576,18 @@ static int ch9_postconfig (struct usbtest_dev *dev) continue; /* [9.4.10] set_interface */ - retval = set_altsetting (dev, i); + retval = set_altsetting (dev, alt); if (retval) { dev_dbg (&iface->dev, "can't set_interface = %d, %d\n", - i, retval); + alt, retval); return retval; } /* [9.4.4] get_interface always works */ retval = get_altsetting (dev); - if (retval != i) { + if (retval != alt) { dev_dbg (&iface->dev, "get alt should be %d, was %d\n", - i, retval); + alt, retval); return (retval < 0) ? retval : -EDOM; } -- cgit v1.2.3 From c868e47d1a6c244e3296f5bfc2c1921fcb5c1929 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Mar 2004 20:53:48 -0800 Subject: [PATCH] USB: remove act_altsetting usages in the remaining drivers/usb/ drivers --- drivers/usb/input/ati_remote.c | 2 +- drivers/usb/input/hid-core.c | 2 +- drivers/usb/input/mtouchusb.c | 2 +- drivers/usb/net/usbnet.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 28377a40142e..8343eead2018 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -700,7 +700,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de return -ENOMEM; memset(ati_remote, 0x00, sizeof (struct ati_remote)); - iface_host = &interface->altsetting[interface->act_altsetting]; + iface_host = interface->cur_altsetting; if (iface_host->desc.bNumEndpoints != 2) { err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); retval = -ENODEV; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 2a5bd976f51b..fc1f3aa0cf80 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1445,7 +1445,7 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) static struct hid_device *usb_hid_configure(struct usb_interface *intf) { - struct usb_host_interface *interface = intf->altsetting + intf->act_altsetting; + struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_device *hid; diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index f0733bebc263..4c80c3ec52ef 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -217,7 +217,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i } dbg("%s - setting interface", __FUNCTION__); - interface = &intf->altsetting[intf->act_altsetting]; + interface = intf->cur_altsetting; dbg("%s - setting endpoint", __FUNCTION__); endpoint = &interface->endpoint[0].desc; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 4104df1af9d3..10d77daaa6be 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -3009,7 +3009,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) return -ENODEV; } xdev = interface_to_usbdev (udev); - interface = &udev->altsetting [udev->act_altsetting]; + interface = udev->cur_altsetting; usb_get_dev (xdev); -- cgit v1.2.3 From 667a8226c541749f54364fd092419d4c292b3ca1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Mar 2004 20:54:08 -0800 Subject: [PATCH] USB: remove act_altsetting usages in more USB drivers --- drivers/input/joystick/iforce/iforce-usb.c | 2 +- drivers/net/irda/stir4200.c | 3 +-- drivers/usb/input/usbkbd.c | 2 +- drivers/usb/input/usbmouse.c | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index a2cefd078385..617c0b0e5a39 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -135,7 +135,7 @@ static int iforce_usb_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; - interface = &intf->altsetting[intf->act_altsetting]; + interface = intf->cur_altsetting; epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 8a82fe444e56..18d39b156d56 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -1086,8 +1086,7 @@ static struct net_device_stats *stir_net_get_stats(struct net_device *dev) static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf) { struct usb_device *usbdev = interface_to_usbdev(intf); - const struct usb_host_interface *interface - = &intf->altsetting[intf->act_altsetting]; + const struct usb_host_interface *interface = intf->cur_altsetting; const struct usb_endpoint_descriptor *ep_in = NULL; const struct usb_endpoint_descriptor *ep_out = NULL; int i; diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index c4c06251c5f5..0c51b1eb84cf 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -240,7 +240,7 @@ static int usb_kbd_probe(struct usb_interface *iface, char path[64]; char *buf; - interface = &iface->altsetting[iface->act_altsetting]; + interface = iface->cur_altsetting; if (interface->desc.bNumEndpoints != 1) return -ENODEV; diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index e293da9399ba..5bf27306ea3c 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -131,7 +131,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ char path[64]; char *buf; - interface = &intf->altsetting[intf->act_altsetting]; + interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != 1) return -ENODEV; -- cgit v1.2.3 From 07fd2b87fca9fb39a7d2626283291ce3861e1b5e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Mar 2004 20:54:26 -0800 Subject: [PATCH] USB: remove intf->act_altsetting altogether from the USB core and usb.h --- drivers/usb/core/message.c | 3 --- include/linux/usb.h | 5 ----- 2 files changed, 8 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 76226e37bb36..5bd4d8ab05ad 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -969,7 +969,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) usb_disable_interface(dev, iface); iface->cur_altsetting = alt; - iface->act_altsetting = alt - iface->altsetting; /* If the interface only has one altsetting and the device didn't * accept the request, we attempt to carry out the equivalent action @@ -1068,7 +1067,6 @@ int usb_reset_configuration(struct usb_device *dev) alt = &intf->altsetting[0]; intf->cur_altsetting = alt; - intf->act_altsetting = alt - intf->altsetting; usb_enable_interface(dev, intf); } return 0; @@ -1170,7 +1168,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) alt = &intf->altsetting[0]; intf->cur_altsetting = alt; - intf->act_altsetting = alt - intf->altsetting; usb_enable_interface(dev, intf); intf->dev.parent = &dev->dev; intf->dev.driver = NULL; diff --git a/include/linux/usb.h b/include/linux/usb.h index e7e102afcb20..eb34f2ee39ea 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -77,10 +77,6 @@ struct usb_host_interface { * endpoint configurations. They will be in no particular order. * @num_altsetting: number of altsettings defined. * @cur_altsetting: the current altsetting. - * @act_altsetting: index of current altsetting. This number is always - * less than num_altsetting. After the device is configured, each - * interface uses its default setting of zero. - * NOTE: act_altsetting is deprecated. Use cur_altsetting instead. * @driver: the USB driver that is bound to this interface. * @minor: the minor number assigned to this interface, if this * interface is bound to a driver that uses the USB major number. @@ -125,7 +121,6 @@ struct usb_interface { struct usb_host_interface *cur_altsetting; /* the currently * active alternate setting */ - unsigned act_altsetting; /* index of active alternate setting: DEPRECATED */ unsigned num_altsetting; /* number of alternate settings */ struct usb_driver *driver; /* driver */ -- cgit v1.2.3 From 118d79a88355267f310de2526dc204897666cba5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 3 Mar 2004 01:01:21 -0800 Subject: [PATCH] USB: HCD names, for better troubleshooting See the attached patch -- which restores the behavior of usbcore to what it had before "struct device.name" went away, in the (typical) case of PCI devices. It makes the root hubs say what hardware they're actually using, in the reasonably typical case that PCI names are in use, rather than being just generic (and hence almost useless) strings. This sort of information can really help when troubleshooting. --- drivers/usb/core/hcd-pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 374657e997d6..ee34642f2039 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -147,8 +147,12 @@ clean_2: hcd->driver = driver; hcd->description = driver->description; hcd->self.bus_name = pci_name(dev); +#ifdef CONFIG_PCI_NAMES + hcd->product_desc = dev->pretty_name; +#else if (hcd->product_desc == NULL) hcd->product_desc = "USB Host Controller"; +#endif hcd->self.controller = &dev->dev; if ((retval = hcd_buffer_create (hcd)) != 0) { -- cgit v1.2.3 From 536a5db55fcd97c48c6c3d21dcc0e1850e544d26 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 7 Mar 2004 19:11:32 -0800 Subject: merge fixups with irda usb code --- drivers/net/irda/stir4200.c | 46 --------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index d3f541e1b657..59bc5d86873e 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -1040,52 +1040,6 @@ static struct net_device_stats *stir_net_get_stats(struct net_device *dev) return &stir->stats; } -/* - * Parse the various endpoints and find the one we need. - * - * The endpoint are the pipes used to communicate with the USB device. - * The spec defines 2 endpoints of type bulk transfer, one in, and one out. - * These are used to pass frames back and forth with the dongle. - */ -static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - const struct usb_host_interface *interface = intf->cur_altsetting; - const struct usb_endpoint_descriptor *ep_in = NULL; - const struct usb_endpoint_descriptor *ep_out = NULL; - int i; - - if (interface->desc.bNumEndpoints != 2) { - WARNING("%s: expected two endpoints\n", __FUNCTION__); - return -ENODEV; - } - - for(i = 0; i < interface->desc.bNumEndpoints; i++) { - const struct usb_endpoint_descriptor *ep - = &interface->endpoint[i].desc; - - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) { - /* We need to find an IN and an OUT */ - if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) - ep_in = ep; - else - ep_out = ep; - } else - WARNING("%s: unknown endpoint type 0x%x\n", - __FUNCTION__, ep->bmAttributes); - } - - if (!ep_in || !ep_out) - return -EIO; - - stir->tx_bulkpipe = usb_sndbulkpipe(usbdev, - ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - stir->rx_intpipe = usb_rcvintpipe(usbdev, - ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - return 0; -} - /* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in -- cgit v1.2.3 From 976814bb828beecef9ca456a0b79bba90b9c78c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 7 Mar 2004 19:53:02 -0800 Subject: USB: fix the pcwd_usb driver due to act_altsetting going away. --- drivers/char/watchdog/pcwd_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 7dbe8fee0b8f..d88228eb5b36 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -589,7 +589,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi } /* get the active interface descriptor */ - iface_desc = &interface->altsetting[interface->act_altsetting]; + iface_desc = interface->cur_altsetting; /* check out that we have a HID device */ if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) { -- cgit v1.2.3 From 1c2dd3251cd75396d9cbc67b74dafce956ef690f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 7 Mar 2004 19:53:44 -0800 Subject: USB: fix usb-serial core to look at the proper interface descriptor --- drivers/usb/serial/usb-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c7a96102a73e..62327d19c175 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1006,7 +1006,7 @@ int usb_serial_probe(struct usb_interface *interface, /* descriptor matches, let's find the endpoints needed */ /* check out the endpoints */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; -- cgit v1.2.3 From 40c72cb00fb4bcebf8c543bab7544adeeaa1836e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 7 Mar 2004 23:07:07 -0800 Subject: [PATCH] USB: Update USB class drivers This patch makes the necessary updates to the bluetty, cdc-acm, and usblp class drivers for the new interface/altsetting paradigm. The changes are quite small. Unfortunately, the audio and usb-midi drivers are in much worse shape. They will require more in-depth hacking, to come later... --- drivers/usb/class/bluetty.c | 2 +- drivers/usb/class/cdc-acm.c | 6 +++--- drivers/usb/class/usblp.c | 9 ++++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c index d3764c8a8bd6..0ae754e2f50d 100644 --- a/drivers/usb/class/bluetty.c +++ b/drivers/usb/class/bluetty.c @@ -1025,7 +1025,7 @@ static int usb_bluetooth_probe (struct usb_interface *intf, int num_bulk_in = 0; int num_bulk_out = 0; - interface = &intf->altsetting[0]; + interface = intf->cur_altsetting; control_out_endpoint = interface->desc.bInterfaceNumber; /* find the endpoints that we need */ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index deaa3c7aa63f..ed02dfde9f26 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -595,12 +595,12 @@ static int acm_probe (struct usb_interface *intf, * is there it's not for call management ... so use * the cdc union descriptor whenever there is one. */ - ifcom = intf->altsetting + 0; + ifcom = intf->cur_altsetting; if (intf == cfacm->interface[j]) { - ifdata = cfacm->interface[j + 1]->altsetting + 0; + ifdata = cfacm->interface[j + 1]->cur_altsetting; data = cfacm->interface[j + 1]; } else if (intf == cfacm->interface[j + 1]) { - ifdata = cfacm->interface[j]->altsetting + 0; + ifdata = cfacm->interface[j]->cur_altsetting; data = cfacm->interface[j]; } else continue; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 97b71cc184fe..e6a453590615 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -133,6 +133,7 @@ struct usblp { wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ int ifnum; /* Interface number */ + struct usb_interface *intf; /* The interface */ /* Alternate-setting numbers and endpoints for each protocol * (7/1/{index=1,2,3}) that the device supports: */ struct { @@ -837,7 +838,8 @@ static int usblp_probe(struct usb_interface *intf, usblp->dev = dev; init_MUTEX (&usblp->sem); init_waitqueue_head(&usblp->wait); - usblp->ifnum = intf->altsetting->desc.bInterfaceNumber; + usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + usblp->intf = intf; usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { @@ -973,7 +975,7 @@ static int usblp_select_alts(struct usblp *usblp) struct usb_endpoint_descriptor *epd, *epwrite, *epread; int p, i, e; - if_alt = usblp->dev->actconfig->interface[usblp->ifnum]; + if_alt = usblp->intf; for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) usblp->protocol[p].alt_setting = -1; @@ -1022,7 +1024,8 @@ static int usblp_select_alts(struct usblp *usblp) epread = NULL; } - usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = i; + usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = + ifd->desc.bAlternateSetting; usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite; usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread; } -- cgit v1.2.3 From 2d5185c7a2ecd97c8bfd498333af0a3955a71b26 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 7 Mar 2004 23:07:27 -0800 Subject: [PATCH] USB: Remove interface/altsettings assumption from audio driver This patch updates the USB audio class driver to use the usb_ifnum_to_if() and usb_altnum_to_altsetting() routines, thereby removing assumptions about which interface or altsetting is stored in which array entry. It also simplifies the driver's probe() routine by using the raw configuration descriptor already loaded into memory instead of reading the descriptor from the device. Now, either the current driver has a bug and never deallocates the buffer used to hold the descriptor, or else I've introduced a double-free error. There's no obvious place where the buffer gets freed, but it's hard to be certain. It would be good if someone could try out this patch. I can't test it, not having any USB audio devices handy. If the double-free error is present, it will show up when the device is disconnected and the configuration data is released. --- drivers/usb/class/audio.c | 135 +++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 74 deletions(-) diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c index ef136e105526..4aa22357675d 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -102,6 +102,9 @@ * 2003-04-08: Oliver Neukum (oliver@neukum.name): * Setting a configuration is done by usbcore and must not be overridden * 2004-02-27: Workaround for broken synch descriptors + * 2004-03-07: Alan Stern + * Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support. + * Use the in-memory descriptors instead of reading them from the device. * */ @@ -143,8 +146,8 @@ * * How does the parsing work? First, all interfaces are searched * for an AudioControl class interface. If found, the config descriptor - * that belongs to the current configuration is fetched from the device. - * Then the HEADER descriptor is fetched. It contains a list of + * that belongs to the current configuration is searched and + * the HEADER descriptor is found. It contains a list of * all AudioStreaming and MIDIStreaming devices. This list is then walked, * and all AudioStreaming interfaces are classified into input and output * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming @@ -1514,7 +1517,6 @@ static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fm static int set_format_in(struct usb_audiodev *as) { struct usb_device *dev = as->state->usbdev; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct usbin *u = &as->usbin; @@ -1524,9 +1526,9 @@ static int set_format_in(struct usb_audiodev *as) unsigned char data[3]; int fmtnr, ret; - if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces) + iface = usb_ifnum_to_if(dev, u->interface); + if (!iface) return 0; - iface = config->interface[u->interface]; fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate); if (fmtnr < 0) { @@ -1535,7 +1537,7 @@ static int set_format_in(struct usb_audiodev *as) } fmt = as->fmtin + fmtnr; - alts = &iface->altsetting[fmt->altsetting]; + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); u->format = fmt->format; u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); u->syncpipe = u->syncinterval = 0; @@ -1556,7 +1558,8 @@ static int set_format_in(struct usb_audiodev *as) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting)); + dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", + u->interface, fmt->altsetting)); if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1603,7 +1606,6 @@ static int set_format_in(struct usb_audiodev *as) static int set_format_out(struct usb_audiodev *as) { struct usb_device *dev = as->state->usbdev; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct usbout *u = &as->usbout; @@ -1613,9 +1615,9 @@ static int set_format_out(struct usb_audiodev *as) unsigned char data[3]; int fmtnr, ret; - if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces) + iface = usb_ifnum_to_if(dev, u->interface); + if (!iface) return 0; - iface = config->interface[u->interface]; fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate); if (fmtnr < 0) { @@ -1625,7 +1627,7 @@ static int set_format_out(struct usb_audiodev *as) fmt = as->fmtout + fmtnr; u->format = fmt->format; - alts = &iface->altsetting[fmt->altsetting]; + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); u->syncpipe = u->syncinterval = 0; if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) { @@ -1652,7 +1654,8 @@ static int set_format_out(struct usb_audiodev *as) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting)); + dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", + u->interface, fmt->altsetting)); if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -2701,7 +2704,6 @@ static int usb_audio_release(struct inode *inode, struct file *file) struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; struct usb_audio_state *s; struct usb_device *dev; - struct usb_interface *iface; lock_kernel(); s = as->state; @@ -2711,19 +2713,15 @@ static int usb_audio_release(struct inode *inode, struct file *file) down(&open_sem); if (file->f_mode & FMODE_WRITE) { usbout_stop(as); - if (dev && as->usbout.interface >= 0) { - iface = dev->actconfig->interface[as->usbout.interface]; - usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0); - } + if (dev && as->usbout.interface >= 0) + usb_set_interface(dev, as->usbout.interface, 0); dmabuf_release(&as->usbout.dma); usbout_release(as); } if (file->f_mode & FMODE_READ) { usbin_stop(as); - if (dev && as->usbin.interface >= 0) { - iface = dev->actconfig->interface[as->usbin.interface]; - usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0); - } + if (dev && as->usbin.interface >= 0) + usb_set_interface(dev, as->usbin.interface, 0); dmabuf_release(&as->usbin.dma); usbin_release(as); } @@ -2828,12 +2826,11 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b { struct usb_device *dev = s->usbdev; struct usb_audiodev *as; - struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface *iface; struct audioformat *fp; unsigned char *fmt, *csep; - unsigned int i, j, k, format; + unsigned int i, j, k, format, idx; if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL))) return; @@ -2874,9 +2871,10 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b /* search for input formats */ if (asifin >= 0) { as->usbin.flags = FLG_CONNECTED; - iface = config->interface[asifin]; - for (i = 0; i < iface->num_altsetting; i++) { - alts = &iface->altsetting[i]; + iface = usb_ifnum_to_if(dev, asifin); + for (idx = 0; idx < iface->num_altsetting; idx++) { + alts = &iface->altsetting[idx]; + i = alts->desc.bAlternateSetting; if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) continue; if (alts->desc.bNumEndpoints < 1) { @@ -2955,14 +2953,15 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b /* search for output formats */ if (asifout >= 0) { as->usbout.flags = FLG_CONNECTED; - iface = config->interface[asifout]; - for (i = 0; i < iface->num_altsetting; i++) { - alts = &iface->altsetting[i]; + iface = usb_ifnum_to_if(dev, asifout); + for (idx = 0; idx < iface->num_altsetting; idx++) { + alts = &iface->altsetting[idx]; + i = alts->desc.bAlternateSetting; if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) continue; if (alts->desc.bNumEndpoints < 1) { /* altsetting 0 should never have iso EPs */ - if (alts->desc.bAlternateSetting != 0) + if (i != 0) printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", dev->devnum, asifout, i); continue; @@ -3659,8 +3658,8 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif) { struct usb_audio_state *s; - struct usb_host_config *config = dev->actconfig; struct usb_interface *iface; + struct usb_host_interface *alt; unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES]; unsigned char *p1; unsigned int i, j, k, numifin = 0, numifout = 0; @@ -3689,54 +3688,63 @@ static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, un dev->devnum, ctrlif); for (i = 0; i < p1[7]; i++) { j = p1[8+i]; - if (j >= config->desc.bNumInterfaces) { + iface = usb_ifnum_to_if(dev, j); + if (!iface) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n", dev->devnum, ctrlif, j); continue; } - iface = config->interface[j]; - if (iface->altsetting[0].desc.bInterfaceClass != USB_CLASS_AUDIO) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n", - dev->devnum, ctrlif, j); + if (iface->num_altsetting == 1) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif); continue; } - if (iface->altsetting[0].desc.bInterfaceSubClass == 3) { - printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n", + alt = usb_altnum_to_altsetting(iface, 0); + if (!alt) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n", dev->devnum, ctrlif, j); continue; } - if (iface->altsetting[0].desc.bInterfaceSubClass != 2) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n", + if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n", dev->devnum, ctrlif, j); continue; } - if (iface->num_altsetting == 0) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif); + if (alt->desc.bInterfaceSubClass == 3) { + printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n", + dev->devnum, ctrlif, j); continue; } - if (iface->num_altsetting == 1) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif); + if (alt->desc.bInterfaceSubClass != 2) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n", + dev->devnum, ctrlif, j); continue; } - if (iface->altsetting[0].desc.bNumEndpoints > 0) { + if (alt->desc.bNumEndpoints > 0) { /* Check all endpoints; should they all have a bandwidth of 0 ? */ - for (k = 0; k < iface->altsetting[0].desc.bNumEndpoints; k++) { - if (iface->altsetting[0].endpoint[k].desc.wMaxPacketSize > 0) { + for (k = 0; k < alt->desc.bNumEndpoints; k++) { + if (alt->endpoint[k].desc.wMaxPacketSize > 0) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k); break; } } - if (k < iface->altsetting[0].desc.bNumEndpoints) + if (k < alt->desc.bNumEndpoints) continue; } - if (iface->altsetting[1].desc.bNumEndpoints < 1) { + + alt = usb_altnum_to_altsetting(iface, 1); + if (!alt) { + printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n", + dev->devnum, ctrlif, j); + continue; + } + if (alt->desc.bNumEndpoints < 1) { printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n", dev->devnum, ctrlif, j); continue; } /* note: this requires the data endpoint to be ep0 and the optional sync ep to be ep1, which seems to be the case */ - if (iface->altsetting[1].endpoint[0].desc.bEndpointAddress & USB_DIR_IN) { + if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) { if (numifin < USB_MAXINTERFACES) { ifin[numifin++] = j; usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1); @@ -3783,12 +3791,9 @@ static int usb_audio_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev (intf); - struct usb_host_config *config = dev->actconfig; struct usb_audio_state *s; unsigned char *buffer; - unsigned char buf[8]; - unsigned int i, buflen; - int ret; + unsigned int buflen; #if 0 printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum, @@ -3800,26 +3805,8 @@ static int usb_audio_probe(struct usb_interface *intf, * audiocontrol interface found * find which configuration number is active */ - i = dev->actconfig - config; - - ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8); - if (ret < 0) { - printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); - return -EIO; - } - if (buf[1] != USB_DT_CONFIG || buf[0] < 9) { - printk(KERN_ERR "usbaudio: invalid config descriptor %d of device %d\n", i, dev->devnum); - return -EIO; - } - buflen = buf[2] | (buf[3] << 8); - if (!(buffer = kmalloc(buflen, GFP_KERNEL))) - return -ENOMEM; - ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen); - if (ret < 0) { - kfree(buffer); - printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret); - return -EIO; - } + buffer = dev->rawdescriptors[dev->actconfig - dev->config]; + buflen = dev->actconfig->desc.wTotalLength; s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber); if (s) { usb_set_intfdata (intf, s); -- cgit v1.2.3 From 593f48d6f4cfb0b0ea7d598121699cd247a3e02d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sun, 7 Mar 2004 23:07:52 -0800 Subject: [PATCH] USB UHCI: restore more state following PM resume Some systems don't save the internal state of the UHCI registers across a PM suspend/resume cycle very well. This patch saves & restores the Frame Number and the Framelist Base Address registers (in addition to the Interrupt Enable register, which was added separately in a recent patch.) --- drivers/usb/host/uhci-hcd.c | 14 ++++++++++---- drivers/usb/host/uhci-hcd.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 876b8364ab88..a8182d88e7b2 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2444,9 +2444,11 @@ static int uhci_suspend(struct usb_hcd *hcd, u32 state) struct uhci_hcd *uhci = hcd_to_uhci(hcd); /* Don't try to suspend broken motherboards, reset instead */ - if (suspend_allowed(uhci)) + if (suspend_allowed(uhci)) { suspend_hc(uhci); - else + uhci->saved_framenumber = + inw(uhci->io_addr + USBFRNUM) & 0x3ff; + } else reset_hc(uhci); return 0; } @@ -2460,9 +2462,13 @@ static int uhci_resume(struct usb_hcd *hcd) if (uhci->state == UHCI_SUSPENDED) { /* - * Some systems clear the Interrupt Enable register during - * PM suspend/resume, so reinitialize it. + * Some systems don't maintain the UHCI register values + * during a PM suspend/resume cycle, so reinitialize + * the Frame Number, the Framelist Base Address, and the + * Interrupt Enable registers. */ + outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM); + outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, uhci->io_addr + USBINTR); uhci->resume_detect = 1; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index fb380d7c8e1e..9c7fa5213dda 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -350,6 +350,7 @@ struct uhci_hcd { enum uhci_state state; /* FIXME: needs a spinlock */ unsigned long state_end; /* Time of next transition */ int resume_detect; /* Need a Global Resume */ + unsigned int saved_framenumber; /* Save during PM suspend */ /* Main list of URB's currently controlled by this HC */ spinlock_t urb_list_lock; -- cgit v1.2.3 From 26375db9172f03087d4295729e9af2019d45750a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Mar 2004 17:47:03 -0800 Subject: [PATCH] USB: Interface/altsetting update for ISDN hisax driver On Mon, 8 Mar 2004, Greg KH wrote: > Oh, could you look at drivers/isdn/hisax/hfc_usb.c if you get a chance? > I tried to figure out the mess there with regards to act_altsetting, but > gave up :( You're right, it is a mess. Beats me why they didn't use a plain old "for" statement to do that altsetting loop. Probably the most confusing part is where the code needlessly resets intf->act_altsetting. Anyway, this patch sets things right. I haven't tried to compile it, but any errors ought to be pretty small, obvious, and easy to fix. My intention was to go through the files under driver/usb (in alphabetical order!) and then do the ones outside that subtree -- I've got a little list. But it's no problem to take care of this one first. --- drivers/isdn/hisax/hfc_usb.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 9707d28cbc76..a04ba318198c 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -1349,9 +1349,11 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ { struct usb_device *dev= interface_to_usbdev(intf); hfcusb_data *context; - struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting; + struct usb_host_interface *iface = intf->cur_altsetting; + struct usb_host_interface *iface_used; struct usb_host_endpoint *ep; - int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; + int ifnum = iface->desc.bInterfaceNumber; + int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0; // usb_show_device(dev); @@ -1366,7 +1368,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", - intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor); + ifnum, iface->desc.bAlternateSetting, intf->minor); #endif if (vend_idx != 0xffff) { @@ -1374,14 +1376,15 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name); #endif /* if vendor and product ID is OK, start probing a matching alternate setting ... */ - probe_alt_setting = 0; + alt_idx = 0; small_match=0xffff; // default settings iso_packet_size=16; packet_size=64; - while(probe_alt_setting < intf->num_altsetting) { - iface = intf->altsetting + probe_alt_setting; + while (alt_idx < intf->num_altsetting) { + iface = intf->altsetting + alt_idx; + probe_alt_setting = iface->desc.bAlternateSetting; cfg_used=0; #ifdef VERBOSE_USB_DEBUG @@ -1395,7 +1398,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n", - probe_alt_setting, intf->act_altsetting,cfg_used); + ifnum, probe_alt_setting, cfg_used); #endif // copy table memcpy(cmptbl,vcf,16*sizeof(int)); @@ -1448,6 +1451,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ if (cfg_used < small_match) { small_match = cfg_used; alt_used = probe_alt_setting; + iface_used = iface; } #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used); @@ -1457,15 +1461,14 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ cfg_used++; } - probe_alt_setting++; - } /* (probe_alt_setting < intf->num_altsetting) */ + alt_idx++; + } /* (alt_idx < intf->num_altsetting) */ #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used); #endif // yiipiee, we found a valid config if (small_match != 0xffff) { - intf->act_altsetting = alt_used; - iface = intf->altsetting + intf->act_altsetting; + iface = iface_used; if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) return(-ENOMEM); /* got no mem */ @@ -1542,8 +1545,8 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ // now share our luck context->dev = dev; /* save device */ - context->if_used = intf->altsetting->desc.bInterfaceNumber; /* save used interface */ - context->alt_used = intf->act_altsetting; /* and alternate config */ + context->if_used = ifnum; /* save used interface */ + context->alt_used = alt_used; /* and alternate config */ context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ context->cfg_used=vcf[16]; // store used config context->vend_idx=vend_idx; // store found vendor -- cgit v1.2.3 From 268f26283a8ce50a31ebcde11c0426433d5f1446 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 8 Mar 2004 17:47:21 -0800 Subject: [PATCH] USB: fix compiler warning in hfc_usb.c driver. --- drivers/isdn/hisax/hfc_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index a04ba318198c..ae47cd1b5863 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -1350,7 +1350,7 @@ static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_ struct usb_device *dev= interface_to_usbdev(intf); hfcusb_data *context; struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_host_interface *iface_used; + struct usb_host_interface *iface_used = NULL; struct usb_host_endpoint *ep; int ifnum = iface->desc.bInterfaceNumber; int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr; -- cgit v1.2.3 From 25a1f19aa12e6a92315d64559380fce7b4ffe2e0 Mon Sep 17 00:00:00 2001 From: Stéphane Doyon Date: Mon, 8 Mar 2004 22:12:08 -0800 Subject: [PATCH] USB brlvger: Driver obsoleted by rewrite using usbfs We have rewritten the brlvger (Tieman Voyager USB Braille display) driver so that it works from user-space through usbfs. It appears to work just as well as the in-kernel driver. The brlvger driver in the 2.6.x kernel is now obsolete and should be removed. The attached patch against 2.6.3 does this. Please apply. NB: The following files are completely deleted: Documentation/usb/brlvger.txt drivers/usb/misc/brlvger.c include/linux/brlvger.h The new Voyager driver is available (stil under GPL) as part of BRLTTY, starting with version 3.5pre1 (http://mielke.cc/brltty). Thanks to Dave Mielke who implemented BRLTTY's usbfs functionality, among lots of other stuff. --- CREDITS | 10 - Documentation/usb/brlvger.txt | 36 -- MAINTAINERS | 7 - drivers/usb/Makefile | 1 - drivers/usb/misc/Kconfig | 11 - drivers/usb/misc/Makefile | 1 - drivers/usb/misc/brlvger.c | 1016 ----------------------------------------- include/linux/brlvger.h | 54 --- 8 files changed, 1136 deletions(-) delete mode 100644 Documentation/usb/brlvger.txt delete mode 100644 drivers/usb/misc/brlvger.c delete mode 100644 include/linux/brlvger.h diff --git a/CREDITS b/CREDITS index 13eba329ee16..6a9a80876d86 100644 --- a/CREDITS +++ b/CREDITS @@ -673,11 +673,6 @@ S: Northampton S: NN1 3QT S: United Kingdom -N: Stephane Dalton -E: sdalton@videotron.ca -D: Tieman Voyager USB Braille display driver. -S: Québec, Canada - N: Uwe Dannowski E: Uwe.Dannowski@ira.uka.de W: http://i30www.ira.uka.de/~dannowsk/ @@ -797,11 +792,6 @@ E: cort@fsmlabs.com W: http://www.fsmlabs.com/linuxppcbk.html D: PowerPC -N: Stéphane Doyon -E: s.doyon@videotron.ca -D: Tieman Voyager USB Braille display driver. -S: Québec, Canada - N: Oleg Drokin E: green@ccssu.crimea.ua W: http://www.ccssu.crimea.ua/~green diff --git a/Documentation/usb/brlvger.txt b/Documentation/usb/brlvger.txt deleted file mode 100644 index e1441ec2558a..000000000000 --- a/Documentation/usb/brlvger.txt +++ /dev/null @@ -1,36 +0,0 @@ -Kernel Driver for the Tieman Voyager Braille Display (USB) - -Authors: -Stéphane Dalton -Stéphane Doyon - -Version 0.8, April 17, 2002 - -The brlvger driver supports a Braille display (aka Braille terminal) -model Voyager from Tieman. - -The driver has been in heavy use for about six months now (as of April -17th 2002) by a very few users (about 3-4), who say it has worked very -well for them. - -We have tested it with a Voyager 44, but it should also support -the Voyager 70. - -This driver implements a character device which allows userspace programs -access to the braille displays raw functions. You still need a userspace -program to perform the screen-review functions and control the -display. Get BRLTTY from http://mielke.cc/brltty/ (version 2.99.8 or -later). It has a Voyager driver which interfaces with this kernel driver. - -The interface is through a character device, major 180, minor 128, called -"brlvger" under devfs. - -Many thanks to the Tieman people: Corand van Strien, Ivar Illing, Daphne -Vogelaar and Ingrid Vogel. They provided us with a Braille display (as -well as programming information) so that we could write this driver. They -replaced the display when it broke and they answered our technical -questions. It is very motivating when companies take an interest in such -projects and are so supportive. - -Thanks to Andor Demarteau who got this whole -project started and beta-tested all our early buggy attempts. diff --git a/MAINTAINERS b/MAINTAINERS index b6ce0c77a2bd..b6640c1b494d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1966,13 +1966,6 @@ P: Romain Lievin M: roms@lpg.ticalc.org S: Maintained -TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER -P: Stephane Dalton -M: sdalton@videotron.ca -P: Stéphane Doyon -M: s.doyon@videotron.ca -S: Maintained - TLAN NETWORK DRIVER P: Samuel Chessman M: chessman@tux.org diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 6e3a98f12605..0baa243f4019 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BRLVGER) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 958574645158..9ab0a65441da 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -86,17 +86,6 @@ config USB_LEGOTOWER a module, say M here and read . -config USB_BRLVGER - tristate "Tieman Voyager USB Braille display support (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - help - Say Y here if you want to use the Voyager USB Braille display from - Tieman. See for more - information. - - To compile this driver as a module, choose M here: the - module will be called brlvger. - config USB_LCD tristate "USB LCD driver support" depends on USB diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 9f0f638af248..2ee829568c04 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -4,7 +4,6 @@ # obj-$(CONFIG_USB_AUERSWALD) += auerswald.o -obj-$(CONFIG_USB_BRLVGER) += brlvger.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_LCD) += usblcd.o diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c deleted file mode 100644 index 067d81730b2e..000000000000 --- a/drivers/usb/misc/brlvger.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Tieman Voyager braille display USB driver. - * - * Copyright 2001-2002 Stephane Dalton - * and Stéphane Doyon - * Maintained by Stéphane Doyon . - */ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* History: - * 0.8 April 2002: Integration into the kernel tree. - * 0.7 October 2001: First public release as a module, distributed with - * the BRLTTY package (beta versions around 2.99y). - */ - -#define DRIVER_VERSION "v0.8" -#define DATE "April 2002" -#define DRIVER_AUTHOR \ - "Stephane Dalton " \ - "and Stéphane Doyon " -#define DRIVER_DESC "Tieman Voyager braille display USB driver for Linux 2.4" -#define DRIVER_SHORTDESC "Voyager" - -#define BANNER \ - KERN_INFO DRIVER_SHORTDESC " " DRIVER_VERSION " (" DATE ")\n" \ - KERN_INFO " by " DRIVER_AUTHOR "\n" - -static const char longbanner[] = { - DRIVER_DESC ", " DRIVER_VERSION " (" DATE "), by " DRIVER_AUTHOR -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - -/* Module parameters */ - -static int debug = 1; -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug level, 0-3"); - -static int write_repeats = 2; -MODULE_PARM(write_repeats, "i"); -MODULE_PARM_DESC(write_repeats, "Hack: repetitions for command to " - "display braille pattern"); - /* to get rid of weird extra dots (perhaps only on - early hardware versions?) */ - -static int stall_tries = 3; -MODULE_PARM(stall_tries, "i"); -MODULE_PARM_DESC(stall_tries, "Hack: retransmits of stalled USB " - "control messages"); - /* broken early hardware versions? */ - -#define BRLVGER_RAW_VOLTAGE 89 -/* from 0->300V to 255->200V, we are told 265V is normal operating voltage, - but we don't know the scale. Assuming it is linear. */ -static int raw_voltage = BRLVGER_RAW_VOLTAGE; -MODULE_PARM(raw_voltage, "i"); -MODULE_PARM_DESC(raw_voltage, "Parameter for the call to SET_DISPLAY_VOLTAGE"); - - -/* protocol and display type defines */ -#define MAX_BRLVGER_CELLS 72 -#define MAX_INTERRUPT_DATA 8 -/* control message request types */ -#define BRLVGER_READ_REQ 0xC2 -#define BRLVGER_WRITE_REQ 0x42 -/* control message request codes */ -#define BRLVGER_SET_DISPLAY_ON 0 -#define BRLVGER_SET_DISPLAY_VOLTAGE 1 -#define BRLVGER_GET_SERIAL 3 -#define BRLVGER_GET_HWVERSION 4 -#define BRLVGER_GET_FWVERSION 5 -#define BRLVGER_GET_LENGTH 6 -#define BRLVGER_SEND_BRAILLE 7 -#define BRLVGER_BEEP 9 -#if 0 /* not used and not sure they're working */ -#define BRLVGER_GET_DISPLAY_VOLTAGE 2 -#define BRLVGER_GET_CURRENT 8 -#endif - -/* Prototypes */ -static int brlvger_probe (struct usb_interface *intf, - const struct usb_device_id *id); -static void brlvger_disconnect(struct usb_interface *intf); -static int brlvger_open(struct inode *inode, struct file *file); -static int brlvger_release(struct inode *inode, struct file *file); -static ssize_t brlvger_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos); -static ssize_t brlvger_read(struct file *file, char __user *buffer, - size_t count, loff_t *unused_pos); -static int brlvger_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg); -static unsigned brlvger_poll(struct file *file, poll_table *wait); -static loff_t brlvger_llseek(struct file * file, loff_t offset, int orig); -static void intr_callback(struct urb *urb, struct pt_regs *regs); -struct brlvger_priv; -static int brlvger_get_hw_version(struct brlvger_priv *priv, - unsigned char *verbuf); -static int brlvger_get_fw_version(struct brlvger_priv *priv, - unsigned char *buf); -static int brlvger_get_serial(struct brlvger_priv *priv, - unsigned char *buf); -static int brlvger_get_display_length(struct brlvger_priv *priv); -static int brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on); -static int brlvger_beep(struct brlvger_priv *priv, __u16 duration); -static int brlvger_set_display_voltage(struct brlvger_priv *priv, - __u16 voltage); -static int mycontrolmsg(const char *funcname, - struct brlvger_priv *priv, unsigned pipe_dir, - __u8 request, __u8 requesttype, __u16 value, - __u16 index, void *data, __u16 size); - -#define controlmsg(priv,pipe_dir,a,b,c,d,e,f) \ - mycontrolmsg(__FUNCTION__, priv, pipe_dir, \ - a,b,c,d,e,f) -#define sndcontrolmsg(priv,a,b,c,d,e,f) \ - controlmsg(priv, 0, a,b,c,d,e,f) -#define rcvcontrolmsg(priv,a,b,c,d,e,f) \ - controlmsg(priv, USB_DIR_IN, a,b,c,d,e,f) - -/* ----------------------------------------------------------------------- */ - -/* Data */ - -/* key event queue size */ -#define MAX_INTERRUPT_BUFFER 10 - -/* private state */ -struct brlvger_priv { - struct usb_device *dev; /* USB device handle */ - struct usb_endpoint_descriptor *in_interrupt; - struct urb *intr_urb; - - int subminor; /* which minor dev #? */ - - unsigned char hwver[BRLVGER_HWVER_SIZE]; /* hardware version */ - unsigned char fwver[BRLVGER_FWVER_SIZE]; /* firmware version */ - unsigned char serialnum[BRLVGER_SERIAL_SIZE]; - - int llength; /* logical length */ - int plength; /* physical length */ - - __u8 obuf[MAX_BRLVGER_CELLS]; - __u8 intr_buff[MAX_INTERRUPT_DATA]; - __u8 event_queue[MAX_INTERRUPT_BUFFER][MAX_INTERRUPT_DATA]; - atomic_t intr_idx, read_idx; - spinlock_t intr_idx_lock; /* protects intr_idx */ - wait_queue_head_t read_wait; - - int opened; - struct semaphore open_sem; /* protects ->opened */ - struct semaphore dev_sem; /* protects ->dev */ -}; - -/* Globals */ - -/* For blocking open */ -static DECLARE_WAIT_QUEUE_HEAD(open_wait); - -/* Some print macros */ -#ifdef dbg -#undef dbg -#endif -#ifdef info -#undef info -#endif -#ifdef err -#undef err -#endif -#define info(args...) \ - ({ printk(KERN_INFO "Voyager: " args); \ - printk("\n"); }) -#define err(args...) \ - ({ printk(KERN_ERR "Voyager: " args); \ - printk("\n"); }) -#define dbgprint(fmt, args...) \ - ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \ - printk("\n"); }) -#define dbg(args...) \ - ({ if(debug >= 1) dbgprint(args); }) -#define dbg2(args...) \ - ({ if(debug >= 2) dbgprint(args); }) -#define dbg3(args...) \ - ({ if(debug >= 3) dbgprint(args); }) - -/* ----------------------------------------------------------------------- */ - -/* Driver registration */ - -static struct usb_device_id brlvger_ids [] = { - { USB_DEVICE(0x0798, 0x0001) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, brlvger_ids); - -static struct file_operations brlvger_fops = -{ - .owner = THIS_MODULE, - .llseek = brlvger_llseek, - .read = brlvger_read, - .write = brlvger_write, - .ioctl = brlvger_ioctl, - .open = brlvger_open, - .release = brlvger_release, - .poll = brlvger_poll, -}; - -static struct usb_class_driver brlvger_class = { - .name = "usb/brlvger%d", - .fops = &brlvger_fops, - .mode = S_IFCHR | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP, - .minor_base = BRLVGER_MINOR, -}; - -static struct usb_driver brlvger_driver = -{ - .owner = THIS_MODULE, - .name = "brlvger", - .probe = brlvger_probe, - .disconnect = brlvger_disconnect, - .id_table = brlvger_ids, -}; - -static int -__init brlvger_init (void) -{ - int retval; - printk(BANNER); - - if(stall_tries < 1 || write_repeats < 1) - return -EINVAL; - - retval = usb_register(&brlvger_driver); - if (retval) { - err("USB registration failed"); - goto out; - } - -out: - return retval; -} - -static void -__exit brlvger_cleanup (void) -{ - usb_deregister (&brlvger_driver); - dbg("Driver unregistered"); -} - -module_init (brlvger_init); -module_exit (brlvger_cleanup); - -/* ----------------------------------------------------------------------- */ - -/* Probe and disconnect functions */ - -static int -brlvger_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct brlvger_priv *priv = NULL; - int retval; - struct usb_endpoint_descriptor *endpoint; - struct usb_host_interface *actifsettings; - /* protects against reentrance: once we've found a free slot - we reserve it.*/ - static DECLARE_MUTEX(reserve_sem); - - actifsettings = dev->actconfig->interface[0]->altsetting; - - if( dev->descriptor.bNumConfigurations != 1 - || dev->config->desc.bNumInterfaces != 1 - || actifsettings->desc.bNumEndpoints != 1 ) { - err ("Bogus braille display config info"); - return -ENODEV; - } - - endpoint = &actifsettings->endpoint [0].desc; - if (!(endpoint->bEndpointAddress & 0x80) || - ((endpoint->bmAttributes & 3) != 0x03)) { - err ("Bogus braille display config info, wrong endpoints"); - return -ENODEV; - } - - down(&reserve_sem); - - retval = usb_register_dev(intf, &brlvger_class); - if (retval) { - err("Not able to get a minor for this device."); - goto error; - } - - if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){ - err("No more memory"); - goto error; - } - - memset(priv, 0, sizeof(*priv)); - atomic_set(&priv->intr_idx, 0); - atomic_set(&priv->read_idx, MAX_INTERRUPT_BUFFER-1); - spin_lock_init(&priv->intr_idx_lock); - init_waitqueue_head(&priv->read_wait); - /* opened is memset'ed to 0 */ - init_MUTEX(&priv->open_sem); - init_MUTEX(&priv->dev_sem); - - priv->subminor = intf->minor; - - /* we found a interrupt in endpoint */ - priv->in_interrupt = endpoint; - - priv->dev = dev; - - if(brlvger_get_hw_version(priv, priv->hwver) <0) { - err("Unable to get hardware version"); - goto error; - } - dbg("Hw ver %d.%d", priv->hwver[0], priv->hwver[1]); - if(brlvger_get_fw_version(priv, priv->fwver) <0) { - err("Unable to get firmware version"); - goto error; - } - dbg("Fw ver: %s", priv->fwver); - - if(brlvger_get_serial(priv, priv->serialnum) <0) { - err("Unable to get serial number"); - goto error; - } - dbg("Serial number: %s", priv->serialnum); - - if( (priv->llength = brlvger_get_display_length(priv)) <0 ){ - err("Unable to get display length"); - goto error; - } - switch(priv->llength) { - case 48: - priv->plength = 44; - break; - case 72: - priv->plength = 70; - break; - default: - err("Unsupported display length: %d", priv->llength); - goto error; - }; - dbg("Display length: %d", priv->plength); - - usb_set_intfdata (intf, priv); - info( "Braille display %d is device major %d minor %d", - intf->minor, USB_MAJOR, BRLVGER_MINOR + intf->minor); - - /* Tell anyone waiting on a blocking open */ - wake_up_interruptible(&open_wait); - - goto out; - - error: - if(priv) { - kfree( priv ); - priv = NULL; - } - - out: - up(&reserve_sem); - if (priv) { - usb_set_intfdata (intf, priv); - return 0; - } - return -EIO; -} - -static void -brlvger_disconnect(struct usb_interface *intf) -{ - struct brlvger_priv *priv = usb_get_intfdata (intf); - int r; - - usb_set_intfdata (intf, NULL); - if(priv){ - info("Display %d disconnecting", priv->subminor); - - usb_deregister_dev(intf, &brlvger_class); - - down(&priv->open_sem); - down(&priv->dev_sem); - if(priv->opened) { - /* Disable interrupts */ - if((r = usb_unlink_urb(priv->intr_urb)) <0) - err("usb_unlink_urb returns %d", r); - usb_free_urb(priv->intr_urb); - /* mark device as dead and prevent control - messages to it */ - priv->dev = NULL; - /* Tell anyone hung up on a read that it - won't be coming */ - wake_up_interruptible(&priv->read_wait); - up(&priv->dev_sem); - up(&priv->open_sem); - }else - /* no corresponding up()s */ - kfree(priv); - } -} - -/* ----------------------------------------------------------------------- */ - -/* fops implementation */ - -static int -brlvger_open(struct inode *inode, struct file *file) -{ - int devnum = iminor(inode); - struct usb_interface *intf = NULL; - struct brlvger_priv *priv = NULL; - int n, ret; - - if (devnum < 0) - return -ENXIO; - - n = devnum - BRLVGER_MINOR; - - do { - intf = usb_find_interface(&brlvger_driver, devnum); - if (!intf) { - if (file->f_flags & O_NONBLOCK) { - dbg3("Failing non-blocking open: " - "device %d not connected", n); - return -EAGAIN; - } - /* Blocking open. One global wait queue will - suffice. We wait until a device for the selected - minor is connected. */ - dbg2("Waiting for device %d to be connected", n); - ret = wait_event_interruptible(open_wait, - (intf = usb_find_interface(&brlvger_driver, devnum))); - if (ret) { - dbg2("Interrupted wait for device %d", n); - return ret; - } - } - } while(!intf); - priv = usb_get_intfdata(intf); - - /* We grabbed an existing device. */ - if(down_interruptible(&priv->open_sem)) - return -ERESTARTSYS; - - /* Only one process can open each device, no sharing. */ - ret = -EBUSY; - if(priv->opened) - goto out; - - dbg("Opening display %d", priv->subminor); - - /* Setup interrupt handler for receiving key input */ - priv->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if(!priv->intr_urb) { - err("Unable to allocate URB"); - goto out; - } - usb_fill_int_urb( priv->intr_urb, priv->dev, - usb_rcvintpipe(priv->dev, - priv->in_interrupt->bEndpointAddress), - priv->intr_buff, sizeof(priv->intr_buff), - intr_callback, priv, priv->in_interrupt->bInterval); - if((ret = usb_submit_urb(priv->intr_urb, GFP_KERNEL)) <0){ - err("Error %d while submitting URB", ret); - goto out; - } - - /* Set voltage */ - if(brlvger_set_display_voltage(priv, raw_voltage) <0) { - err("Unable to set voltage"); - goto out; - } - - /* Turn display on */ - if((ret = brlvger_set_display_on_off(priv, 1)) <0) { - err("Error %d while turning display on", ret); - goto out; - } - - /* Mark as opened, so disconnect cannot free priv. */ - priv->opened = 1; - - file->private_data = priv; - - ret = 0; - goto out; - - out: - up(&priv->open_sem); - return ret; -} - -static int -brlvger_release(struct inode *inode, struct file *file) -{ - struct brlvger_priv *priv = file->private_data; - int r; - - /* Turn display off. Safe even if disconnected. */ - brlvger_set_display_on_off(priv, 0); - - /* mutex with disconnect and with open */ - down(&priv->open_sem); - - if(!priv->dev) { - dbg("Releasing disconnected device %d", priv->subminor); - /* no up(&priv->open_sem) */ - kfree(priv); - }else{ - dbg("Closing display %d", priv->subminor); - /* Disable interrupts */ - if((r = usb_unlink_urb(priv->intr_urb)) <0) - err("usb_unlink_urb returns %d", r); - usb_free_urb(priv->intr_urb); - priv->opened = 0; - up(&priv->open_sem); - } - - return 0; -} - -static ssize_t -brlvger_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - struct brlvger_priv *priv = file->private_data; - char buf[MAX_BRLVGER_CELLS]; - int ret; - size_t rs; - loff_t off; - __u16 written; - - if(!priv->dev) - return -ENOLINK; - - off = *pos; - - if(off > priv->plength) - return -ESPIPE;; - - rs = priv->plength - off; - - if(count > rs) - count = rs; - written = count; - - if (copy_from_user (buf, buffer, count ) ) - return -EFAULT; - - memset(priv->obuf, 0xaa, sizeof(priv->obuf)); - - /* Firmware supports multiples of 8cells, so some cells are absent - and for some reason there actually are holes! euurkkk! */ - - if( priv->plength == 44 ) { - /* Two ghost cells at the beginning of the display, plus - two more after the sixth physical cell. */ - if(off > 5) { - off +=4; - memcpy(priv->obuf, buf, count); - }else{ - int firstpart = 6 - off; - -#ifdef WRITE_DEBUG - dbg3("off: %lld, rs: %d, count: %d, firstpart: %d", - off, rs, count, firstpart); -#endif - - firstpart = (firstpart < count) ? firstpart : count; - -#ifdef WRITE_DEBUG - dbg3("off: %lld", off); - dbg3("firstpart: %d", firstpart); -#endif - - memcpy(priv->obuf, buf, firstpart); - - if(firstpart != count) { - int secondpart = count - firstpart; -#ifdef WRITE_DEBUG - dbg3("secondpart: %d", secondpart); -#endif - - memcpy(priv->obuf+(firstpart+2), - buf+firstpart, secondpart); - written +=2; - } - - off +=2; - -#ifdef WRITE_DEBUG - dbg3("off: %lld, rs: %d, count: %d, firstpart: %d, " - "written: %d", off, rs, count, firstpart, written); -#endif - } - }else{ - /* Two ghost cells at the beginningg of the display. */ - memcpy(priv->obuf, buf, count); - off += 2; - } - - { - int repeat = write_repeats; - /* Dirty hack: sometimes some of the dots are wrong and somehow - right themselves if the command is repeated. */ - while(repeat--) { - ret = sndcontrolmsg(priv, - BRLVGER_SEND_BRAILLE, BRLVGER_WRITE_REQ, 0, - off, priv->obuf, written); - if(ret <0) - return ret; - } - } - - return count; -} - -static int -read_index(struct brlvger_priv *priv) -{ - int intr_idx, read_idx; - - read_idx = atomic_read(&priv->read_idx); - read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; - - intr_idx = atomic_read(&priv->intr_idx); - - return(read_idx == intr_idx ? -1 : read_idx); -} - -static ssize_t -brlvger_read(struct file *file, char __user *buffer, - size_t count, loff_t *unused_pos) -{ - struct brlvger_priv *priv = file->private_data; - int read_idx; - - if(count != MAX_INTERRUPT_DATA) - return -EINVAL; - - if(!priv->dev) - return -ENOLINK; - - if((read_idx = read_index(priv)) == -1) { - /* queue empty */ - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - else{ - int r = wait_event_interruptible(priv->read_wait, - (!priv->dev || (read_idx = read_index(priv)) != -1)); - if(!priv->dev) - return -ENOLINK; - if(r) - return r; - if(read_idx == -1) - /* should not happen */ - return 0; - } - } - - if (copy_to_user (buffer, priv->event_queue[read_idx], count) ) - return( -EFAULT); - - atomic_set(&priv->read_idx, read_idx); - /* Multiple opens are not allowed. Yet on SMP, two processes could - read at the same time (on a shared file descriptor); then it is not - deterministic whether or not they will get duplicates of a key - event. */ - return MAX_INTERRUPT_DATA; -} - -static int -brlvger_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return -ENOLINK; - - switch(cmd) { - case BRLVGER_GET_INFO: { - struct brlvger_info vi; - - memset(&vi, 0, sizeof(vi)); - strlcpy(vi.driver_version, DRIVER_VERSION, - sizeof(vi.driver_version)); - strlcpy(vi.driver_banner, longbanner, - sizeof(vi.driver_banner)); - - vi.display_length = priv->plength; - - memcpy(&vi.hwver, priv->hwver, BRLVGER_HWVER_SIZE); - memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE); - memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE); - - if(copy_to_user((void __user *)arg, &vi, sizeof(vi))) - return -EFAULT; - return 0; - } - case BRLVGER_DISPLAY_ON: - return brlvger_set_display_on_off(priv, 1); - case BRLVGER_DISPLAY_OFF: - return brlvger_set_display_on_off(priv, 0); - case BRLVGER_BUZZ: { - __u16 duration; - if(get_user(duration, (__u16 *)arg)) - return -EFAULT; - return brlvger_beep(priv, duration); - } - -#if 0 /* Underlying commands don't seem to work for some reason; not clear if - we'd want to export these anyway. */ - case BRLVGER_SET_VOLTAGE: { - __u16 voltage; - if(get_user(voltage, (__u16 *)arg)) - return -EFAULT; - return brlvger_set_display_voltage(priv, voltage); - } - case BRLVGER_GET_VOLTAGE: { - __u8 voltage; - int r = brlvger_get_display_voltage(priv); - if(r <0) - return r; - voltage = r; - if(put_user(voltage, (__u8 *)arg)) - return -EFAULT; - return 0; - } -#endif - default: - return -EINVAL; - }; -} - -static loff_t -brlvger_llseek(struct file *file, loff_t offset, int orig) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return -ENOLINK; - - switch (orig) { - case 0: - /* nothing to do */ - break; - case 1: - offset +=file->f_pos; - break; - case 2: - offset += priv->plength; - default: - return -EINVAL; - } - - if((offset >= priv->plength) || (offset < 0)) - return -EINVAL; - - return (file->f_pos = offset); -} - -static unsigned -brlvger_poll(struct file *file, poll_table *wait) -{ - struct brlvger_priv *priv = file->private_data; - - if(!priv->dev) - return POLLERR | POLLHUP; - - poll_wait(file, &priv->read_wait, wait); - - if(!priv->dev) - return POLLERR | POLLHUP; - if(read_index(priv) != -1) - return POLLIN | POLLRDNORM; - - return 0; -} - -static void -intr_callback(struct urb *urb, struct pt_regs *regs) -{ - struct brlvger_priv *priv = urb->context; - int intr_idx, read_idx; - int status; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - read_idx = atomic_read(&priv->read_idx); - spin_lock(&priv->intr_idx_lock); - intr_idx = atomic_read(&priv->intr_idx); - if(read_idx == intr_idx) { - dbg2("Queue full, dropping braille display input"); - spin_unlock(&priv->intr_idx_lock); - goto exit; /* queue full */ - } - - memcpy(priv->event_queue[intr_idx], urb->transfer_buffer, - MAX_INTERRUPT_DATA); - - intr_idx = (++intr_idx == MAX_INTERRUPT_BUFFER)? 0 : intr_idx; - atomic_set(&priv->intr_idx, intr_idx); - spin_unlock(&priv->intr_idx_lock); - - wake_up_interruptible(&priv->read_wait); - -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -/* ----------------------------------------------------------------------- */ - -/* Hardware access functions */ - -static int -mycontrolmsg(const char *funcname, - struct brlvger_priv *priv, unsigned pipe_dir, - __u8 request, __u8 requesttype, __u16 value, - __u16 index, void *data, __u16 size) -{ - int ret=0, tries = stall_tries; - - /* Make sure the device was not disconnected */ - if(down_interruptible(&priv->dev_sem)) - return -ERESTARTSYS; - if(!priv->dev) { - up(&priv->dev_sem); - return -ENOLINK; - } - - /* Dirty hack for retransmission: stalls and fails all the time - without this on the hardware we tested. */ - while(tries--) { - ret = usb_control_msg(priv->dev, - usb_sndctrlpipe(priv->dev,0) |pipe_dir, - request, requesttype, value, - index, data, size, - HZ); - if(ret != -EPIPE) - break; - dbg2("Stalled, remaining %d tries", tries); - } - up(&priv->dev_sem); - if(ret <0) { - err("%s: usb_control_msg returns %d", - funcname, ret); - return -EIO; - } - return 0; -} - -static int -brlvger_get_hw_version(struct brlvger_priv *priv, unsigned char *verbuf) -{ - return rcvcontrolmsg(priv, - BRLVGER_GET_HWVERSION, BRLVGER_READ_REQ, 0, - 0, verbuf, BRLVGER_HWVER_SIZE); - /* verbuf should be 2 bytes */ -} - -static int -brlvger_get_fw_version(struct brlvger_priv *priv, unsigned char *buf) -{ - unsigned char rawbuf[(BRLVGER_FWVER_SIZE-1)*2+2]; - int i, len; - int r = rcvcontrolmsg(priv, - BRLVGER_GET_FWVERSION, BRLVGER_READ_REQ, 0, - 0, rawbuf, sizeof(rawbuf)); - if(r<0) - return r; - - /* If I guess correctly: succession of 16bit words, the string is - formed of the first byte of each of these words. First byte in - buffer indicates total length of data; not sure what second byte is - for. */ - len = rawbuf[0]-2; - if(len<0) - len = 0; - else if(len+1 > BRLVGER_FWVER_SIZE) - len = BRLVGER_FWVER_SIZE-1; - for(i=0; i9) ? (n)+'A' : (n)+'0') - buf[2*i] = NUM_TO_HEX(rawserial[i] >>4); - buf[2*i+1] = NUM_TO_HEX(rawserial[i] &0xf); - } - buf[2*i] = 0; - return 0; -} - -static int -brlvger_get_display_length(struct brlvger_priv *priv) -{ - unsigned char data[2]; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_LENGTH, BRLVGER_READ_REQ, 0, - 0, data, 2); - if(ret<0) - return ret; - return data[1]; -} - -static int -brlvger_beep(struct brlvger_priv *priv, __u16 duration) -{ - return sndcontrolmsg(priv, - BRLVGER_BEEP, BRLVGER_WRITE_REQ, duration, - 0, NULL, 0); -} - -static int -brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on) -{ - dbg2("Turning display %s", ((on) ? "on" : "off")); - return sndcontrolmsg(priv, - BRLVGER_SET_DISPLAY_ON, BRLVGER_WRITE_REQ, on, - 0, NULL, 0); -} - -static int -brlvger_set_display_voltage(struct brlvger_priv *priv, __u16 voltage) -{ - dbg("SET_DISPLAY_VOLTAGE to %u", voltage); - return sndcontrolmsg(priv, - BRLVGER_SET_DISPLAY_VOLTAGE, BRLVGER_WRITE_REQ, voltage, - 0, NULL, 0); -} - -#if 0 /* Had problems testing these commands. Not particularly useful anyway.*/ - -static int -brlvger_get_display_voltage(struct brlvger_priv *priv) -{ - __u8 voltage = 0; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_DISPLAY_VOLTAGE, BRLVGER_READ_REQ, 0, - 0, &voltage, 1); - if(ret<0) - return ret; - return voltage; -} - -static int -brlvger_get_current(struct brlvger_priv *priv) -{ - unsigned char data; - int ret = rcvcontrolmsg(priv, - BRLVGER_GET_CURRENT, BRLVGER_READ_REQ, 0, - 0, &data, 1); - if(ret<0) - return ret; - return data; -} -#endif diff --git a/include/linux/brlvger.h b/include/linux/brlvger.h deleted file mode 100644 index 388f3fdb6cc9..000000000000 --- a/include/linux/brlvger.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Tieman Voyager braille display USB driver. - * - * Copyright 2001-2002 Stephane Dalton - * and Stéphane Doyon - * Maintained by Stéphane Doyon . - */ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_BRLVGER_H -#define _LINUX_BRLVGER_H - -/* Ioctl request codes */ -#define BRLVGER_GET_INFO 0 -#define BRLVGER_DISPLAY_ON 2 -#define BRLVGER_DISPLAY_OFF 3 -#define BRLVGER_BUZZ 4 - -/* Base minor for the char devices */ -#define BRLVGER_MINOR 128 - -/* Size of some fields */ -#define BRLVGER_HWVER_SIZE 2 -#define BRLVGER_FWVER_SIZE 200 /* arbitrary, a long string */ -#define BRLVGER_SERIAL_BIN_SIZE 8 -#define BRLVGER_SERIAL_SIZE ((2*BRLVGER_SERIAL_BIN_SIZE)+1) - -struct brlvger_info { - __u8 driver_version[12]; - __u8 driver_banner[200]; - - __u32 display_length; - /* All other char[] fields are strings except this one. - Hardware version: first byte is major, second byte is minor. */ - __u8 hwver[BRLVGER_HWVER_SIZE]; - __u8 fwver[BRLVGER_FWVER_SIZE]; - __u8 serialnum[BRLVGER_SERIAL_SIZE]; -}; - -#endif -- cgit v1.2.3 From d4bf939394ea8e2559bbaaac1e34ec3998ed5cfa Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Mon, 8 Mar 2004 22:12:30 -0800 Subject: [PATCH] USB: 2.6 pegasus.h updates a few more IDs added, could you please apply it? --- drivers/usb/net/pegasus.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 6518d5a41970..52832af7ed18 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -128,6 +128,7 @@ struct usb_eth_dev { #define VENDOR_DLINK 0x2001 #define VENDOR_ELCON 0x0db7 #define VENDOR_ELSA 0x05cc +#define VENDOR_GIGABYTE 0x1044 #define VENDOR_HAWKING 0x0e66 #define VENDOR_HP 0x03f0 #define VENDOR_IODATA 0x04bb @@ -178,6 +179,9 @@ PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet", VENDOR_ADMTEK, 0x8513, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet", + VENDOR_ADMTEK, 0x8515, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)", VENDOR_ADMTEK, 0x0986, DEFAULT_GPIO_RESET | HAS_HOME_PNA ) @@ -223,6 +227,8 @@ PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, @@ -263,6 +269,8 @@ PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, -- cgit v1.2.3 From 10443b9ffc04b44efac6c32ea9033993c619c0c1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 01:25:08 -0800 Subject: [PATCH] USB: usbnet and ALI M5632 Some of the 480 Mbit/sec USB host-to-host links have ALI chips in them. They seem to work with no problem, given this patch, even when the ends talk different speed. --- drivers/usb/net/Kconfig | 8 ++++++++ drivers/usb/net/usbnet.c | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 93f5ea96130c..74c99e6d1589 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -131,6 +131,14 @@ config USB_USBNET comment "USB Host-to-Host Cables" depends on USB_USBNET +config USB_ALI_M5632 + boolean "ALi M5632 based 'USB 2.0 Data Link' cables" + depends on USB_USBNET + default y + help + Choose this option if you're using a host-to-host cable + based on this design, which supports USB 2.0 high speed. + config USB_AN2720 boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)" depends on USB_USBNET diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 10d77daaa6be..dc5617b71552 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -383,6 +383,23 @@ static void skb_return (struct usbnet *dev, struct sk_buff *skb) devdbg (dev, "netif_rx status %d", status); } + +#ifdef CONFIG_USB_ALI_M5632 +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * ALi M5632 driver ... does high speed + * + *-------------------------------------------------------------------------*/ + +static const struct driver_info ali_m5632_info = { + .description = "ALi M5632", +}; + + +#endif + #ifdef CONFIG_USB_AN2720 #define HAVE_HARDWARE @@ -3133,6 +3150,13 @@ out: static const struct usb_device_id products [] = { +#ifdef CONFIG_USB_ALI_M5632 +{ + USB_DEVICE (0x0402, 0x5632), // ALi defaults + .driver_info = (unsigned long) &ali_m5632_info, +}, +#endif + #ifdef CONFIG_USB_AN2720 { USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults -- cgit v1.2.3 From 1a89696e81dddaedb6229efb0febeba3aeb36d5c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 01:25:33 -0800 Subject: [PATCH] USB: gadget config buf utilities Somehow I sent you a version of this code with a misplaced semicolon ... it makes for awkward failures! Please merge. Bad semicolon! --- drivers/usb/gadget/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 3437b92f66cd..531909242b24 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -52,7 +52,7 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen, for (; 0 != *src; src++) { unsigned len = (*src)->bLength; - if (len > buflen); + if (len > buflen) return -EINVAL; memcpy(dest, *src, len); buflen -= len; -- cgit v1.2.3 From ba6f837d12920f82a17d19cdc7e1ae0aa260906d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 01:25:56 -0800 Subject: [PATCH] USB: clarify CONFIG_USB_GADGET Marc-Christian Petersen wrote: > > I think the attached patch is needed to stop showing us USB Gadget support if > Support for USB is disabled. No it isn't. But maybe the attached patch would clarify what's really going on: CONFIG_USB is the host side, and CONFIG_USB_GADGET is the peripheral side. --- drivers/usb/Kconfig | 44 ++++++++++++++++++++++++-------------------- drivers/usb/gadget/Kconfig | 11 ++++++++++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 27a2e91313bd..4c74401ae557 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -6,32 +6,36 @@ menu "USB support" # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB - tristate "Support for USB" + tristate "Support for Host-side USB" depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the traditional PC serial port. The bus supplies power to peripherals and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB port in a tree structure. The USB port is - the root of the tree, the peripherals are the leaves and the inner - nodes are special USB devices called hubs. Many newer PC's have USB - ports and newer peripherals such as scanners, keyboards, mice, - modems, and printers support the USB protocol and can be connected - to the PC via those ports. - - Say Y here if your computer has a USB port and you want to use USB - devices. You then need to say Y to at least one of "UHCI HCD support" - or "OHCI HCD support" below (the type of interface that the USB hardware - in your computer provides to the operating system) and then choose - from amongst the drivers for USB peripherals. You may want to check - out the information provided in and - especially the links given in . - - If you have a new USB 2.0 High Speed system, you should also choose - "EHCI HCD (USB 2.0) support" as well as at least one of UHCI or OHCI. - - It doesn't normally hurt to select them all if you are not certain. + connected to a single USB host in a tree structure. + + The USB host is the root of the tree, the peripherals are the + leaves and the inner nodes are special USB devices called hubs. + Most PCs now have USB host ports, used to connect peripherals + such as scanners, keyboards, mice, modems, cameras, disks, + flash memory, network links, and printers to the PC. + + Say Y here if your computer has a host-side USB port and you want + to use USB devices. You then need to say Y to at least one of the + Host Controller Driver (HCD) options below. Choose a USB 1.1 + controller, such as "UHCI HCD support" or "OHCI HCD support", + and "EHCI HCD (USB 2.0) support" except for older systems that + do not have USB 2.0 support. It doesn't normally hurt to select + them all if you are not certain. + + If your system has a device-side USB port, used in the peripheral + side of the USB protocol, see the "USB Gadget" framework instead. + + After choosing your HCD, then select drivers for the USB peripherals + you'll be using. You may want to check out the information provided + in and especially the links given in + . To compile this driver as a module, choose M here: the module will be called usbcore. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 38e9f6a2a2bf..5f8dc0606d23 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -3,6 +3,15 @@ # (a) a peripheral controller, and # (b) the gadget driver using it. # +# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! +# +# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). +# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). +# - Some systems have both kinds of of controller. +# +# With help from a special transceiver and a "Mini-AB" jack, systems with +# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). +# menu "USB Gadget Support" config USB_GADGET @@ -11,7 +20,7 @@ config USB_GADGET USB is a master/slave protocol, organized with one master host (such as a PC) controlling up to 127 peripheral devices. The USB hardware is asymmetric, which makes it easier to set up: - you can't connect two "to-the-host" connectors to each other. + you can't connect a "to-the-host" connector to a peripheral. Linux can run in the host, or in the peripheral. In both cases you need a low level bus controller driver, and some software -- cgit v1.2.3 From c3ca41bec8d3747be012fe5985198910f3e6deaa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 9 Mar 2004 19:55:44 -0800 Subject: [PATCH] USB: fix stack usage in pl2303 driver Arghh - while trying to follow this I just realized the pl2303 is DMA'ing to the stack - not good! Could you please just try with the patch below. I'm not sure if this might cause the MA620 trouble but it's definedly a bug and maybe it improves things for you... --- drivers/usb/serial/pl2303.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index bda130391e53..bf226d3cd81f 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -403,7 +403,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) { struct termios tmp_termios; struct usb_serial *serial = port->serial; - unsigned char buf[10]; + unsigned char *buf; int result; if (port_paranoia_check (port, __FUNCTION__)) @@ -414,6 +414,10 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); + buf = kmalloc(10, GFP_KERNEL); + if (buf==NULL) + return -ENOMEM; + #define FISH(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ b, a, c, d, buf, 1, 100); \ @@ -433,6 +437,8 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + kfree(buf); + /* Setup termios */ if (port->tty) { pl2303_set_termios (port, &tmp_termios); -- cgit v1.2.3 From e29852f848b489179d0cebd299f4205ac9ed8adf Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 9 Mar 2004 20:20:24 -0800 Subject: [PATCH] USB: locking fix for pid.c you forgot to drop a spinlock before you report an error. A deadlock will occur. --- drivers/usb/input/pid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c index 4426660bd7c2..a38b0db8dcea 100644 --- a/drivers/usb/input/pid.c +++ b/drivers/usb/input/pid.c @@ -200,6 +200,7 @@ static int hid_pid_upload_effect(struct input_dev *dev, break; if ( id == FF_EFFECTS_MAX) { + spin_unlock_irqrestore(&pid_private->lock,flags); // TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) { dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n"); return -ENOMEM; -- cgit v1.2.3 From c5cd1f9d0e0505a36cd435fd006b9f6a9b89ce9e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 9 Mar 2004 20:20:55 -0800 Subject: [PATCH] USB: Remove interface/altsetting assumptions from usb-midi This patch makes the usb-midi driver use usb_ifnum_to_if(), thereby removing assumptions about which interface is stored in which array entry. Similarly, it stores the bAlternateSetting value rather than the array index for an altsetting entry. Like the earlier patch for the audio driver, this also changes the driver to use the in-memory rawdescriptor buffer rather than reading a configuration descriptor from the device. Unlike that earlier patch, this time there's no question that the deallocation of the buffer is done correctly. (I suspect the audio driver just left out a call to kfree.) --- drivers/usb/class/usb-midi.c | 93 +++++++++++++------------------------------- 1 file changed, 28 insertions(+), 65 deletions(-) diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c index e817e90c6948..3546b9b9615c 100644 --- a/drivers/usb/class/usb-midi.c +++ b/drivers/usb/class/usb-midi.c @@ -39,9 +39,6 @@ #include #include -/** This declaration is missing from linux/usb.h **/ -extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size); - #include "usb-midi.h" /* ------------------------------------------------------------------------- */ @@ -1519,15 +1516,17 @@ static int on_bits( unsigned short v ) static int get_alt_setting( struct usb_device *d, int ifnum ) { int alts, alt=0; + struct usb_interface *iface; struct usb_host_interface *interface; struct usb_endpoint_descriptor *ep; int epin, epout; int i; - alts = d->actconfig->interface[ifnum]->num_altsetting; + iface = usb_ifnum_to_if( d, ifnum ); + alts = iface->num_altsetting; for ( alt=0 ; altactconfig->interface[ifnum]->altsetting[alt]; + interface = &iface->altsetting[alt]; epin = -1; epout = -1; @@ -1542,7 +1541,7 @@ static int get_alt_setting( struct usb_device *d, int ifnum ) epout = i; } if ( epin >= 0 && epout >= 0 ) { - return alt; + return interface->desc.bAlternateSetting; } } } @@ -1780,12 +1779,13 @@ static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s * Called by usb_midi_probe(); **/ -static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s) +static int detect_yamaha_device( struct usb_device *d, + struct usb_interface *iface, unsigned int ifnum, + struct usb_midi_state *s) { - struct usb_host_config *c = d->actconfig; struct usb_host_interface *interface; struct usb_midi_device *u; - unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; + unsigned char *buffer; int bufSize; int i; int alts=-1; @@ -1795,13 +1795,13 @@ static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struc return -EINVAL; } - for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) { - interface = c->interface[ifnum]->altsetting + i; + for ( i=0 ; i < iface->num_altsetting; i++ ) { + interface = iface->altsetting + i; if ( interface->desc.bInterfaceClass != 255 || interface->desc.bInterfaceSubClass != 0 ) continue; - alts = i; + alts = interface->desc.bAlternateSetting; } if ( alts == -1 ) { return -EINVAL; @@ -1810,30 +1810,11 @@ static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struc printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n", d->descriptor.idVendor, d->descriptor.idProduct, ifnum); - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); - return -EINVAL; - } - if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { - printk(KERN_INFO "usb-midi: config not as expected.\n"); - return -EINVAL; - } - bufSize = buf[2] | buf[3]<<8; - buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); - if ( !buffer ) { - printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); - return -EINVAL; - } - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); - kfree(buffer); - return -EINVAL; - } + i = d->actconfig - d->config; + buffer = d->rawdescriptors[i]; + bufSize = d->actconfig->desc.wTotalLength; u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1); - kfree(buffer); if ( u == NULL ) { return -EINVAL; } @@ -1878,24 +1859,25 @@ static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifn * Returns 0 on success, negative on failure. * Called by usb_midi_probe(); **/ -static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s) +static int detect_midi_subclass(struct usb_device *d, + struct usb_interface *iface, unsigned int ifnum, + struct usb_midi_state *s) { - struct usb_host_config *c = d->actconfig; struct usb_host_interface *interface; struct usb_midi_device *u; - unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; + unsigned char *buffer; int bufSize; int i; int alts=-1; int ret; - for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) { - interface = c->interface[ifnum]->altsetting + i; + for ( i=0 ; i < iface->num_altsetting; i++ ) { + interface = iface->altsetting + i; if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO || interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING ) continue; - alts = i; + alts = interface->desc.bAlternateSetting; } if ( alts == -1 ) { return -EINVAL; @@ -1915,30 +1897,11 @@ static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct descriptor they modify or extend. */ - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); - return -EINVAL; - } - if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { - printk(KERN_INFO "usb-midi: config not as expected.\n"); - return -EINVAL; - } - bufSize = buf[2] | buf[3]<<8; - buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); - if ( !buffer ) { - printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); - return -EINVAL; - } - ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); - if ( ret < 0 ) { - printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); - kfree(buffer); - return -EINVAL; - } + i = d->actconfig - d->config; + buffer = d->rawdescriptors[i]; + bufSize = d->actconfig->desc.wTotalLength; u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0); - kfree(buffer); if ( u == NULL ) { return -EINVAL; } @@ -2002,7 +1965,7 @@ static int usb_midi_probe(struct usb_interface *intf, { struct usb_midi_state *s; struct usb_device *dev = interface_to_usbdev(intf); - int ifnum = intf->altsetting->desc.bInterfaceNumber; + int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL); if ( !s ) @@ -2018,9 +1981,9 @@ static int usb_midi_probe(struct usb_interface *intf, if ( detect_by_hand( dev, ifnum, s ) && - detect_midi_subclass( dev, ifnum, s ) && + detect_midi_subclass( dev, intf, ifnum, s ) && detect_vendor_specific_device( dev, ifnum, s ) && - detect_yamaha_device( dev, ifnum, s) ) { + detect_yamaha_device( dev, intf, ifnum, s) ) { kfree(s); return -EIO; } -- cgit v1.2.3 From f3f3a0ab9f20b3960bfe679b2dd92bae1fd82161 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 9 Mar 2004 20:21:20 -0800 Subject: [PATCH] USB: fixes for aiptek driver - don't pass buffers allocated on stack to the sync helpers - check errors in probe - fix count in open - proper macros --- drivers/usb/input/aiptek.c | 57 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index c0c9080bb714..3aa448533688 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -43,7 +43,8 @@ #include #include #include - +#include +#include /* * Version Information */ @@ -160,9 +161,9 @@ aiptek_irq(struct urb *urb, struct pt_regs *regs) proximity = data[5] & 0x01; input_report_key(dev, BTN_TOOL_PEN, proximity); - x = ((__u32) data[1]) | ((__u32) data[2] << 8); - y = ((__u32) data[3]) | ((__u32) data[4] << 8); - pressure = ((__u32) data[6]) | ((__u32) data[7] << 8); + x = le16_to_cpu(get_unaligned((u16 *) &data[1])); + y = le16_to_cpu(get_unaligned((u16 *) &data[3])); + pressure = le16_to_cpu(*(u16 *) &data[6]); pressure -= aiptek->features->pressure_min; if (pressure < 0) { @@ -209,8 +210,10 @@ aiptek_open(struct input_dev *dev) return 0; aiptek->irq->dev = aiptek->usbdev; - if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) + if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) { + aiptek->open--; return -EIO; + } return 0; } @@ -234,19 +237,27 @@ usb_set_report(struct usb_device *dev, struct usb_host_interface *inter, unsigne (type << 8) + id, inter->desc.bInterfaceNumber, buf, size, HZ); } -static void +static int aiptek_command(struct usb_device *dev, struct usb_host_interface *inter, unsigned char command, unsigned char data) { - __u8 buf[3]; + u8 *buf; + int err; + + buf = kmalloc(3, GFP_KERNEL); + if (!buf) + return -ENOMEM; buf[0] = 4; buf[1] = command; buf[2] = data; - if (usb_set_report(dev, inter, 3, 2, buf, 3) != 3) { + if ((err = usb_set_report(dev, inter, 3, 2, buf, 3)) != 3) { dbg("aiptek_command: 0x%x 0x%x\n", command, data); } + + kfree(buf); + return err < 0 ? err : 0; } static int @@ -257,30 +268,32 @@ aiptek_probe(struct usb_interface *intf, struct usb_host_interface *interface = intf->altsetting + 0; struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; + int err = -ENOMEM; if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL))) - return -ENOMEM; + goto error_out_noalloc; memset(aiptek, 0, sizeof (struct aiptek)); - aiptek->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &aiptek->data_dma); + aiptek->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &aiptek->data_dma); if (!aiptek->data) { - kfree(aiptek); - return -ENOMEM; + goto error_out_nobuf; } aiptek->irq = usb_alloc_urb(0, GFP_KERNEL); if (!aiptek->irq) { - usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); - kfree(aiptek); - return -ENOMEM; + goto error_out_nourb; } /* Resolution500LPI */ - aiptek_command(dev, interface, 0x18, 0x04); + err = aiptek_command(dev, interface, 0x18, 0x04); + if (err) + goto error_out; /* SwitchToTablet */ - aiptek_command(dev, interface, 0x10, 0x01); + err = aiptek_command(dev, interface, 0x10, 0x01); + if (err) + goto error_out; aiptek->features = aiptek_features + id->driver_info; @@ -340,6 +353,16 @@ aiptek_probe(struct usb_interface *intf, usb_set_intfdata(intf, aiptek); return 0; + +error_out: + usb_free_urb(aiptek->irq); +error_out_nourb: + usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma); +error_out_nobuf: + kfree(aiptek); +error_out_noalloc: + return err; + } static void -- cgit v1.2.3 From ddd3d78b7843b83ceec7c2b5f07506c71c62fd81 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 9 Mar 2004 20:21:49 -0800 Subject: [PATCH] USB: bug in error code path of kbtab driver this fixes - a leak in the error code path of open() - removes SLAB_ATOMIC where it isn't needed - uses le16_to_cpu (yes Pete, unaligned access is taken care of) --- drivers/usb/input/kbtab.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index beef425de482..29b515970008 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include /* * Version Information @@ -65,8 +67,8 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - kbtab->x = (data[2] << 8) + data[1]; - kbtab->y = (data[4] << 8) + data[3]; + kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1])); + kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3])); kbtab->pressure = (data[5]); @@ -108,8 +110,10 @@ static int kbtab_open(struct input_dev *dev) return 0; kbtab->irq->dev = kbtab->usbdev; - if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) + if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) { + kbtab->open--; return -EIO; + } return 0; } @@ -133,7 +137,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i return -ENOMEM; memset(kbtab, 0, sizeof(struct kbtab)); - kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma); + kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma); if (!kbtab->data) { kfree(kbtab); return -ENOMEM; -- cgit v1.2.3 From c722dae1a4ee29372b1fd6cfa5ed2fff23075c51 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 9 Mar 2004 20:22:13 -0800 Subject: [PATCH] USB: wacom driver fixes the same error code path as in the other drivers. In addition I added the endianness macros. They save cycles in interrupt. -use endian macros -use GFP_KERNEL where SLAB_ATOMIC is not needed -fix count bug in open() error path --- drivers/usb/input/wacom.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 607de56262d2..e119d2602af7 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -63,6 +63,8 @@ #include #include #include +#include +#include /* * Version Information @@ -194,8 +196,8 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); input_report_key(dev, BTN_TOOL_PEN, 1); - input_report_abs(dev, ABS_X, data[2] << 8 | data[1]); - input_report_abs(dev, ABS_Y, data[4] << 8 | data[3]); + input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((u16 *) &data[1]))); + input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((u16 *) &data[3]))); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); @@ -234,8 +236,8 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) if (data[0] != 2) dbg("received unknown report #%d", data[0]); - x = data[2] | ((__u32)data[3] << 8); - y = data[4] | ((__u32)data[5] << 8); + x = le16_to_cpu(*(u16 *) &data[2]); + y = le16_to_cpu(*(u16 *) &data[4]); input_regs(dev, regs); @@ -269,7 +271,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_report_abs(dev, ABS_Y, y); } - input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(u16 *) &data[6])); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); input_report_key(dev, BTN_STYLUS, data[1] & 0x02); input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); @@ -354,8 +356,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); - input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); + input_report_abs(dev, ABS_X, be16_to_cpu(*(u16 *) &data[2])); + input_report_abs(dev, ABS_Y, be16_to_cpu(*(u16 *) &data[4])); input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ @@ -483,8 +485,10 @@ static int wacom_open(struct input_dev *dev) return 0; wacom->irq->dev = wacom->usbdev; - if (usb_submit_urb(wacom->irq, GFP_KERNEL)) + if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { + wacom->open--; return -EIO; + } return 0; } @@ -509,7 +513,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i return -ENOMEM; memset(wacom, 0, sizeof(struct wacom)); - wacom->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &wacom->data_dma); + wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); if (!wacom->data) { kfree(wacom); return -ENOMEM; -- cgit v1.2.3 From 924eec1ccacfd77f00347257db401f9a5026f929 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 9 Mar 2004 20:22:42 -0800 Subject: [PATCH] USB_STORAGE: remove a comment In 2.6, USB_STORAGE selects SCSI, so there's no longer a need for this comment. --- drivers/usb/storage/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index f830c74dd725..9e49d5477a0d 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -1,8 +1,6 @@ # # USB Storage driver configuration # -comment "SCSI support is needed for USB Storage" - depends on USB && SCSI=n config USB_STORAGE tristate "USB Mass Storage support" -- cgit v1.2.3 From 8ff6915f9e4f5ec5b39811a992b4de729ee61a55 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 9 Mar 2004 20:23:05 -0800 Subject: [PATCH] USB: remove USB_SCANNER MAINTAINERS entry When sending the patch to remove USB_SCANNER, I forgot to remove the MAINTAINERS entry. --- MAINTAINERS | 8 -------- 1 file changed, 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index b6640c1b494d..444f943d0afe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2147,14 +2147,6 @@ L: linux-usb-devel@lists.sourceforge.net W: http://pegasus2.sourceforge.net/ S: Maintained -USB SCANNER DRIVER -P: Henning Meier-Geinitz -M: henning@meier-geinitz.de -L: linux-usb-users@lists.sourceforge.net -L: linux-usb-devel@lists.sourceforge.net -W: http://www.meier-geinitz.de/kernel/ -S: Maintained - USB SE401 DRIVER P: Jeroen Vreeken M: pe1rxq@amsat.org -- cgit v1.2.3 From 1a165cbd801a56a2ab45982a6c0c329500cc9b3a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 9 Mar 2004 20:42:17 -0800 Subject: [PATCH] USB: fix net2280 section usage net2280_remove() is called by net2280_probe() so it shouldn't be marked as __exit; --- drivers/usb/gadget/net2280.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 774cc55b2f4f..5b33e473041f 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2663,7 +2663,7 @@ static void gadget_release (struct device *_dev) /* tear down the binding between this driver and the pci device */ -static void __exit net2280_remove (struct pci_dev *pdev) +static void net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); @@ -2884,7 +2884,7 @@ static struct pci_driver net2280_pci_driver = { .id_table = pci_ids, .probe = net2280_probe, - .remove = __exit_p(net2280_remove), + .remove = net2280_remove, /* FIXME add power management support */ }; -- cgit v1.2.3 From e2d38bf31f0a5a0b66a8ec60c557435498de68ba Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 20:42:44 -0800 Subject: [PATCH] USB: usbcore doc update Some doc updates, mostly from Alan Stern, clarifying quetions folk have asked recently about unlinking and about iso transfers. --- drivers/usb/core/urb.c | 65 +++++++++++++++++++++++++++++++++++++++++--------- include/linux/usb.h | 27 +++++++++++---------- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 39d6c359bcf6..d5a75b1aca52 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -116,7 +116,8 @@ struct urb * usb_get_urb(struct urb *urb) * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink - * (also called "request cancellation"). + * (a software-induced fault, also called "request cancelation"). + * * URBs may be submitted in interrupt context. * * The caller must have correctly initialized the URB before submitting @@ -127,12 +128,23 @@ struct urb * usb_get_urb(struct urb *urb) * * Successful submissions return 0; otherwise this routine returns a * negative error number. If the submission is successful, the complete() - * callback from the urb will be called exactly once, when the USB core and - * host controller driver are finished with the urb. When the completion + * callback from the URB will be called exactly once, when the USB core and + * Host Controller Driver (HCD) are finished with the URB. When the completion * function is called, control of the URB is returned to the device * driver which issued the request. The completion handler may then * immediately free or reuse that URB. * + * With few exceptions, USB device drivers should never access URB fields + * provided by usbcore or the HCD until its complete() is called. + * The exceptions relate to periodic transfer scheduling. For both + * interrupt and isochronous urbs, as part of successful URB submission + * urb->interval is modified to reflect the actual transfer period used + * (normally some power of two units). And for isochronous urbs, + * urb->start_frame is modified to reflect when the URB's transfers were + * scheduled to start. Not all isochronous transfer scheduling policies + * will work, but most host controller drivers should easily handle ISO + * queues going from now until 10-200 msec into the future. + * * For control endpoints, the synchronous usb_control_msg() call is * often used (in non-interrupt context) instead of this call. * That is often used through convenience wrappers, for the requests @@ -143,15 +155,17 @@ struct urb * usb_get_urb(struct urb *urb) * * URBs may be submitted to endpoints before previous ones complete, to * minimize the impact of interrupt latencies and system overhead on data - * throughput. This is required for continuous isochronous data streams, + * throughput. With that queuing policy, an endpoint's queue would never + * be empty. This is required for continuous isochronous data streams, * and may also be required for some kinds of interrupt transfers. Such - * queueing also maximizes bandwidth utilization by letting USB controllers + * queuing also maximizes bandwidth utilization by letting USB controllers * start work on later requests before driver software has finished the - * completion processing for earlier requests. + * completion processing for earlier (successful) requests. * - * Bulk and Isochronous URBs may always be queued. At this writing, all - * mainstream host controller drivers support queueing for control and - * interrupt transfer requests. + * As of Linux 2.6, all USB endpoint transfer queues support depths greater + * than one. This was previously a HCD-specific behavior, except for ISO + * transfers. Non-isochronous endpoint queues are inactive during cleanup + * after faults (transfer errors or cancelation). * * Reserved Bandwidth Transfers: * @@ -389,7 +403,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags) * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this * request is synchronous. Success is indicated by returning zero, * at which time the urb will have been unlinked and its completion - * handler will have been called with urb->status -ENOENT. Failure is + * handler will have been called with urb->status == -ENOENT. Failure is * indicated by any other return value. * * The synchronous cancelation mode may not be used @@ -400,8 +414,37 @@ int usb_submit_urb(struct urb *urb, int mem_flags) * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this * request is asynchronous. Success is indicated by returning -EINPROGRESS, * at which time the urb will normally not have been unlinked. - * The completion function will see urb->status -ECONNRESET. Failure + * The completion function will see urb->status == -ECONNRESET. Failure * is indicated by any other return value. + * + * Unlinking and Endpoint Queues: + * + * Host Controller Driver (HCDs) place all the URBs for a particular + * endpoint in a queue. Normally the queue advances as the controller + * hardware processes each request. But when an URB terminates with any + * fault (such as an error, or being unlinked) its queue stops, at least + * until that URB's completion routine returns. It is guaranteed that + * the queue will not restart until all its unlinked URBs have been fully + * retired, with their completion routines run, even if that's not until + * some time after the original completion handler returns. + * + * This means that USB device drivers can safely build deep queues for + * large or complex transfers, and clean them up reliably after any sort + * of aborted transfer by unlinking all pending URBs at the first fault. + * + * Note that an URB terminating early because a short packet was received + * will count as an error if and only if the URB_SHORT_NOT_OK flag is set. + * Also, that all unlinks performed in any URB completion handler must + * be asynchronous. + * + * Queues for isochronous endpoints are treated differently, because they + * advance at fixed rates. Such queues do not stop when an URB is unlinked. + * An unlinked URB may leave a gap in the stream of packets. It is undefined + * whether such gaps can be filled in. + * + * When control URBs terminates with an error, it is likely that the + * status stage of the transfer will not take place, even if it is merely + * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set. */ int usb_unlink_urb(struct urb *urb) { diff --git a/include/linux/usb.h b/include/linux/usb.h index eb34f2ee39ea..29ef679bd92a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -495,8 +495,8 @@ extern struct bus_type usb_bus_type; * @minor_base: the start of the minor range for this driver. * * This structure is used for the usb_register_dev() and - * usb_unregister_dev() functions, to consolodate a number of the - * paramaters used for them. + * usb_unregister_dev() functions, to consolidate a number of the + * parameters used for them. */ struct usb_class_driver { char *name; @@ -554,7 +554,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * @urb_list: For use by current owner of the URB. * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; - * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl" + * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" * (control), "bulk", "int" (interrupt), or "iso" (isochronous). * For example usb_sndbulkpipe() or usb_rcvintpipe(). Endpoint * numbers range from zero to fifteen. Note that "in" endpoint two @@ -573,8 +573,8 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP * is set). This buffer must be suitable for DMA; allocate it with * kmalloc() or equivalent. For transfers to "in" endpoints, contents - * of this buffer will be modified. This buffer is used for data - * phases of control transfers. + * of this buffer will be modified. This buffer is used for the data + * stage of control transfers. * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, * the device driver is saying that it provided this DMA address, * which the host controller driver should use in preference to the @@ -597,8 +597,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * device driver has provided this DMA address for the setup packet. * The host controller driver should use this in preference to * setup_packet. - * @start_frame: Returns the initial frame for interrupt or isochronous - * transfers. + * @start_frame: Returns the initial frame for isochronous transfers. * @number_of_packets: Lists the number of ISO transfer buffers. * @interval: Specifies the polling interval for interrupt or isochronous * transfers. The units are frames (milliseconds) for for full and low @@ -666,13 +665,14 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * Interrupt UBS must provide an interval, saying how often (in milliseconds * or, for highspeed devices, 125 microsecond units) * to poll for transfers. After the URB has been submitted, the interval - * and start_frame fields reflect how the transfer was actually scheduled. + * field reflects how the transfer was actually scheduled. * The polling interval may be more frequent than requested. * For example, some controllers have a maximum interval of 32 microseconds, * while others support intervals of up to 1024 microseconds. * Isochronous URBs also have transfer intervals. (Note that for isochronous * endpoints, as well as high speed interrupt endpoints, the encoding of - * the transfer interval in the endpoint descriptor is logarithmic.) + * the transfer interval in the endpoint descriptor is logarithmic. + * Device drivers must convert that value to linear units themselves.) * * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling * the host controller to schedule the transfer as soon as bandwidth @@ -705,8 +705,9 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * The context field is normally used to link URBs back to the relevant * driver or request state. * - * When completion callback is invoked for non-isochronous URBs, the - * actual_length field tells how many bytes were transferred. + * When the completion callback is invoked for non-isochronous URBs, the + * actual_length field tells how many bytes were transferred. This field + * is updated even when the URB terminated with an error or was unlinked. * * ISO transfer status is reported in the status and actual_length fields * of the iso_frame_desc array, and the number of errors is reported in @@ -733,9 +734,9 @@ struct urb int actual_length; /* (return) actual transfer length */ unsigned char *setup_packet; /* (in) setup packet (control only) */ dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ - int start_frame; /* (modify) start frame (INT/ISO) */ + int start_frame; /* (modify) start frame (ISO) */ int number_of_packets; /* (in) number of ISO packets */ - int interval; /* (in) transfer interval (INT/ISO) */ + int interval; /* (modify) transfer interval (INT/ISO) */ int error_count; /* (return) number of ISO errors */ int timeout; /* (in) timeout, in jiffies */ void *context; /* (in) context for completion */ -- cgit v1.2.3 From 2328fb17c17ec156481290916ee8d9dc4eceab08 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 21:30:20 -0800 Subject: [PATCH] USB gadget: dualspeed {run,compile}-time flags This is the first several autoconfig patches; please merge. This particular one abstracts dual-speed (high and full) support. Support some more autoconfiguration for gadget drivers. Run-time: * Add gadget->is_dualspeed flag for controllers to set. * Tested by "ethernet" gadget, to decide whether certain operations are errors or not. * Turned on by net2280. Compile-time * Generic CONFIG_USB_GADGET_DUALSPEED, not net2280-specific. * Used by "ethernet" gadget, to decide whether to include extra code and data for dual-speed support. * Turned on by net2280. The basic idea behind this, and other autoconfig patches yet to come, is minimizing the controller-specific compile-time configuration needed by gadget drivers. --- drivers/usb/gadget/Kconfig | 8 ++++++++ drivers/usb/gadget/ether.c | 28 +++++++++++++++------------- drivers/usb/gadget/net2280.c | 1 + include/linux/usb_gadget.h | 3 +++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5f8dc0606d23..f7074d74beae 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -52,6 +52,7 @@ choice config USB_GADGET_NET2280 boolean "NetChip 2280" depends on PCI + select USB_GADGET_DUALSPEED help NetChip 2280 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. @@ -135,6 +136,13 @@ config USB_SA1100 endchoice +config USB_GADGET_DUALSPEED + bool + depends on USB_GADGET + default n + help + Means that gadget drivers should include extra descriptors + and code to handle dual-speed controllers. # # USB Gadget Drivers diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 1ab0afe74f02..aba9f0d3d377 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -124,7 +124,6 @@ struct eth_dev { * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support * WAKEUP ... if hardware supports remote wakeup AND we will issue the * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * @@ -162,7 +161,6 @@ static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 static const char EP_STATUS_NAME [] = "ep-f"; #define EP_STATUS_NUM 3 -#define HIGHSPEED /* supports remote wakeup, but this driver doesn't */ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); @@ -311,7 +309,7 @@ static const char EP_IN_NAME[] = "ep2in-bulk"; #define DEFAULT_QLEN 2 /* double buffering by default */ #endif -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED static unsigned qmult = 5; module_param (qmult, uint, S_IRUGO|S_IWUSR); @@ -324,7 +322,7 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); /* also defer IRQs on highspeed TX */ #define TX_DELAY DEFAULT_QLEN -#else /* !HIGHSPEED ... full speed: */ +#else /* full speed (low speed doesn't do bulk) */ #define qlen(gadget) DEFAULT_QLEN #endif @@ -626,7 +624,7 @@ static const struct usb_descriptor_header *fs_function [] = { 0, }; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -707,7 +705,7 @@ static const struct usb_descriptor_header *hs_function [] = { /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -744,7 +742,7 @@ config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { int len; const struct usb_descriptor_header **function = fs_function; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) @@ -969,7 +967,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) switch (gadget->speed) { case USB_SPEED_FULL: speed = "full"; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: speed = "high"; break; #endif default: speed = "?"; break; @@ -1140,15 +1138,19 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, ctrl->wValue >> 8, @@ -1652,7 +1654,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) #endif req->length = length; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) @@ -1775,7 +1777,7 @@ eth_bind (struct usb_gadget *gadget) #endif device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; #endif @@ -1871,7 +1873,7 @@ fail: /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 5b33e473041f..9a71c7b73281 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2736,6 +2736,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; + dev->gadget.is_dualspeed = 1; /* the "gadget" abstracts/virtualizes the controller */ strcpy (dev->gadget.dev.bus_id, "gadget"); diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 041e2540a48e..04c2622b505d 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -465,6 +465,8 @@ struct usb_gadget_ops { * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. * @name: Identifies the controller hardware type. Used in diagnostics * and sometimes configuration. * @dev: Driver model state for this abstract device. @@ -488,6 +490,7 @@ struct usb_gadget { struct usb_ep *ep0; struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; + unsigned is_dualspeed:1; const char *name; struct device dev; }; -- cgit v1.2.3 From 6df6a80d0312ccabd61415d14bb59186d8adaa1e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 21:30:47 -0800 Subject: [PATCH] USB: usb_unlink_urb() has distinct "not linked" fault This gets rid of an often-bogus diagnostic, and lets at least the unlink test code recover reasonably when it hits that brief window while another CPU has gotten the complete() callback but hasn't yet resubmitted. Return distinct code when unlinking an urb that's not linked. This lets drivers handle this fault sanely, when they need to. Gets rid of annoying non-error messages about drivers that unlink in disconnect() even when the urb isn't linked. --- drivers/usb/core/hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9a803f10a9b4..210877dfb934 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1213,7 +1213,7 @@ static int hcd_unlink_urb (struct urb *urb) break; } if (tmp != &urb->urb_list) { - retval = -EINVAL; + retval = -EIDRM; goto done; } @@ -1294,7 +1294,7 @@ done: spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); bye: - if (retval && sys && sys->driver) + if (retval != -EIDRM && sys && sys->driver) dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; } -- cgit v1.2.3 From 529ba76ce41393cea6a7b6570fe9ab0f7bbb697b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 21:31:12 -0800 Subject: [PATCH] USB: usbtest updates (new firmware) This includes some small updates to "usbtest", mostly from Martin Diehl. Please merge. usbtest updates, supporting new firmware - Support the new usbtest_fw-20040305 EZ-USB firmware, which renumerates and handles full speed ISO transfers. (From Martin Diehl.) - Minor cleanups: use dev_dbg(), let some slightly-off devices work in the control queueing test. - Be pickier about unlink tests: insist that async and sync unlinks give the appropriate fault code. --- drivers/usb/misc/usbtest.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 901cb178f231..646a7884f496 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -149,8 +149,6 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) if (!out) out = e; } - if (in && out) - goto found; continue; try_iso: if (e->desc.bEndpointAddress & USB_DIR_IN) { @@ -160,9 +158,9 @@ try_iso: if (!iso_out) iso_out = e; } - if (iso_in && iso_out) - goto found; } + if ((in && out) || (iso_in && iso_out)) + goto found; } return -EINVAL; @@ -181,7 +179,8 @@ found: in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out_pipe = usb_sndbulkpipe (udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - } else if (iso_in) { + } + if (iso_in) { dev->iso_in = &iso_in->desc; dev->in_iso_pipe = usb_rcvisocpipe (udev, iso_in->desc.bEndpointAddress @@ -211,7 +210,7 @@ static void simple_callback (struct urb *urb, struct pt_regs *regs) static struct urb *simple_alloc_urb ( struct usb_device *udev, int pipe, - long bytes + unsigned long bytes ) { struct urb *urb; @@ -912,7 +911,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); // interface == 0 len = sizeof (struct usb_interface_descriptor); - expected = -EPIPE; + expected = EPIPE; break; // NOTE: two consecutive stalls in the queue here. // that tests fault recovery a bit more aggressively. @@ -941,7 +940,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8); // endpoint == 0 len = sizeof (struct usb_interface_descriptor); - expected = -EPIPE; + expected = EPIPE; break; // NOTE: sometimes even a third fault in the queue! case 12: // get string 0 descriptor (MAY STALL) @@ -1068,7 +1067,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) * due to errors, or is just NAKing requests. */ if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) { - dbg ("submit/unlink fail %d", retval); + dev_dbg (&dev->intf->dev, "submit fail %d\n", retval); return retval; } @@ -1083,18 +1082,22 @@ retry: * "normal" drivers would prevent resubmission, but * since we're testing unlink paths, we can't. */ - dbg ("unlink retry"); + dev_dbg (&dev->intf->dev, "unlink retry\n"); goto retry; } if (!(retval == 0 || retval == -EINPROGRESS)) { - dbg ("submit/unlink fail %d", retval); + dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval); return retval; } wait_for_completion (&completion); retval = urb->status; simple_free_urb (urb); - return retval; + + if (async) + return (retval != -ECONNRESET) ? -ECONNRESET : 0; + else + return (retval != -ENOENT) ? -ENOENT : 0; } static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) @@ -1719,7 +1722,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) retval = unlink_simple (dev, dev->in_pipe, param->length); if (retval) - dbg ("unlink reads failed, iterations left %d", i); + dev_dbg (&intf->dev, "unlink reads failed %d, " + "iterations left %d\n", retval, i); break; case 12: if (dev->out_pipe == 0 || !param->length) @@ -1731,7 +1735,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) retval = unlink_simple (dev, dev->out_pipe, param->length); if (retval) - dbg ("unlink writes failed, iterations left %d", i); + dev_dbg (&intf->dev, "unlink writes failed %d, " + "iterations left %d\n", retval, i); break; /* ep halt tests */ @@ -1961,7 +1966,10 @@ static struct usbtest_info fw_info = { .name = "usb test device", .ep_in = 2, .ep_out = 2, - .alt = 0, + .alt = 1, + .autoconf = 1, // iso and ctrl_out need autoconf + .ctrl_out = 1, + .iso = 1, // iso_ep's are #8 in/out }; /* peripheral running Linux and 'zero.c' test firmware, or -- cgit v1.2.3 From 29a611ab51e01eecca6f87ba6aa55b0ad6cc40d0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 21:31:40 -0800 Subject: [PATCH] USB: usb buffer allocation shouldn't require DMA Deepak's recent dma_pool changes accidentally assumed that all HCDs use DMA. The fix is simple: use kmalloc/kfree when there's no DMA. --- drivers/usb/core/buffer.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index e0ab946d7305..a649e32d9dde 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -51,8 +51,8 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = { * @hcd: the bus whose buffer pools are to be initialized * Context: !in_interrupt() * - * Call this as part of initializing a host controller that uses the pci dma - * memory allocators. It initializes some pools of dma-consistent memory that + * Call this as part of initializing a host controller that uses the dma + * memory allocators. It initializes some pools of dma-coherent memory that * will be shared by all drivers using that controller, or returns a negative * errno value on error. * @@ -115,6 +115,12 @@ void *hcd_buffer_alloc ( struct usb_hcd *hcd = bus->hcpriv; int i; + /* some USB hosts just use PIO */ + if (!bus->controller->dma_mask) { + *dma = ~(dma_addr_t) 0; + return kmalloc (size, mem_flags); + } + for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) return dma_pool_alloc (hcd->pool [i], mem_flags, dma); @@ -134,6 +140,12 @@ void hcd_buffer_free ( if (!addr) return; + + if (!bus->controller->dma_mask) { + kfree (addr); + return; + } + for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) { dma_pool_free (hcd->pool [i], addr, dma); -- cgit v1.2.3 From 3e4a8764a93e314e5f989175d13bd6a17d29a5c8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Mar 2004 21:32:02 -0800 Subject: [PATCH] USB gadget: gadget zero, simplified controller-specific configuration This removes several controller-specific #define, and converts to using the config_buf utilities. Depends on the patch I submitted yesterday. Looking simpler! Simplify "gadget zero" compile-time configuration. This removes several controller-specific compile-time config options; the others are about to be autoconfigured. - HIGHSPEED replaced by CONFIG_USB_GADGET_DUALSPEED - Default to self-powered operation - There's no UI for remote wakeup It also uses the new config_buf utilities, so it's a bit easier to see what's really going on (this driver implements four configurations). --- drivers/usb/gadget/Makefile | 2 +- drivers/usb/gadget/zero.c | 193 +++++++++++++++++++++----------------------- 2 files changed, 94 insertions(+), 101 deletions(-) diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index ed21782ee859..517f86383db3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o # # USB gadget drivers # -g_zero-objs := zero.o usbstring.o +g_zero-objs := zero.o usbstring.o config.o g_ether-objs := ether.o usbstring.o config.o g_serial-objs := serial.o usbstring.o gadgetfs-objs := inode.o usbstring.o diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 704183437a76..11ced77f67b9 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,7 +1,7 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -102,6 +102,11 @@ static const char loopback [] = "loop input to output"; /*-------------------------------------------------------------------------*/ +/* + * driver assumes self-powered hardware, and + * has no way for users to trigger remote wakeup. + */ + /* * hardware-specific configuration, controlled by which device * controller driver was configured. @@ -110,11 +115,6 @@ static const char loopback [] = "loop input to output"; * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * * add other defines for other portability issues, like hardware that * for some reason doesn't handle full speed bulk maxpacket of 64. @@ -138,9 +138,6 @@ static const char EP_OUT_NAME [] = "ep-a"; #define EP_OUT_NUM 2 static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 -#define HIGHSPEED -/* specific hardware configs could be bus-powered */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -161,8 +158,6 @@ static const char EP_OUT_NAME [] = "ep12out-bulk"; #define EP_OUT_NUM 12 static const char EP_IN_NAME [] = "ep11in-bulk"; #define EP_IN_NUM 11 -/* doesn't support bus-powered operation */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -183,8 +178,6 @@ static const char EP_OUT_NAME [] = "ep1out-bulk"; #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2in-bulk"; #define EP_IN_NUM 2 -/* doesn't support bus-powered operation */ -/* doesn't support remote wakeup? */ #endif /* @@ -199,7 +192,6 @@ static const char EP_OUT_NAME [] = "ep1-bulk"; #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2-bulk"; #define EP_IN_NUM 2 -/* doesn't support remote wakeup */ #endif /*-------------------------------------------------------------------------*/ @@ -208,30 +200,6 @@ static const char EP_IN_NAME [] = "ep2-bulk"; # error Configure some USB peripheral controller driver! #endif -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif - /*-------------------------------------------------------------------------*/ /* big enough to hold our biggest descriptor */ @@ -290,8 +258,8 @@ module_param (pattern, uint, S_IRUGO|S_IWUSR); /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to - * work better with hosts (like Linux ... for now!) where config - * changes are problematic. + * work better with hosts where config changes are problematic. + * Or controllers (like superh) that only support one config. */ static int loopdefault = 0; @@ -301,7 +269,7 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR); /* Thanks to NetChip Technologies for donating this product ID. * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ @@ -353,8 +321,8 @@ source_sink_config = { .bNumInterfaces = 1, .bConfigurationValue = CONFIG_SOURCE_SINK, .iConfiguration = STRING_SOURCE_SINK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; static const struct usb_config_descriptor @@ -366,8 +334,8 @@ loopback_config = { .bNumInterfaces = 1, .bConfigurationValue = CONFIG_LOOPBACK, .iConfiguration = STRING_LOOPBACK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; /* one interface in each configuration */ @@ -414,7 +382,21 @@ fs_sink_desc = { .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -425,22 +407,20 @@ fs_sink_desc = { * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; @@ -456,6 +436,20 @@ dev_qualifier = { .bNumConfigurations = 2, }; +static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + +static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -464,13 +458,14 @@ dev_qualifier = { /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static char manufacturer [40]; static char serial [40]; /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, { STRING_LOOPBACK, loopback, }, @@ -502,60 +497,42 @@ static struct usb_gadget_strings stringtab = { * device?) */ static int -config_buf (enum usb_device_speed speed, +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { - int is_source_sink; - const unsigned config_len = USB_DT_CONFIG_SIZE - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; -#ifdef HIGHSPEED - int hs; + int is_source_sink; + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (gadget->speed == USB_SPEED_HIGH); #endif + /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; is_source_sink = loopdefault ? (index == 1) : (index == 0); - /* config (or other speed config) */ - if (is_source_sink) - memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE); - else - memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; - - /* one interface */ - if (is_source_sink) - memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE); - else - memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* the endpoints in that interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + if (hs) + function = is_source_sink + ? hs_source_sink_function + : hs_loopback_function; + else #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - - return config_len; + function = is_source_sink + ? fs_source_sink_function + : fs_loopback_function; + + len = usb_gadget_config_buf (is_source_sink + ? &source_sink_config + : &loopback_config, + buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -1019,17 +996,21 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf (gadget, req->buf, ctrl->wValue >> 8, ctrl->wValue & 0xff); if (value >= 0) @@ -1212,14 +1193,26 @@ zero_bind (struct usb_gadget *gadget) dev->req->complete = zero_setup_complete; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assume ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif gadget->ep0->driver_data = dev; INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME); + + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + return 0; enomem: @@ -1230,7 +1223,7 @@ enomem: /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver zero_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, -- cgit v1.2.3 From bcffdf5cb05fd57b433c2d8c33b471cd3acc02f2 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 9 Mar 2004 21:42:31 -0800 Subject: [PATCH] USB: unusual_devs.h update *** linux-2.6.3/drivers/usb/storage/unusual_devs.h 2004-02-18 04:59:06.000000000 +0100 --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 00ae8b1a9ebd..55fb0233f44c 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -417,6 +417,13 @@ UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Henning Schild */ +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0113, 0x0113, + "EagleTec", + "External Hard Disk", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY ), + /* Reported by Hanno Boeck * Taken from the Lycoris Kernel */ UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, -- cgit v1.2.3 From 8dbe0a71d2fef1253bfcd1c9273abafbebc724f2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 9 Mar 2004 21:44:37 -0800 Subject: [PATCH] USB: Altsetting/interface update for USB image drivers This patch contains minute updates for the hpusbscsi, mdc800, and microtek drivers. Only two things are worth noting. In the mdc800 driver I removed some unnecessary calls to usb_driver_claim_interface(), usb_driver_release_interface(), and usb_set_interface(). Likewise, in the microtek driver I removed an unnecessary call to usb_set_interface(). --- drivers/usb/image/hpusbscsi.c | 2 +- drivers/usb/image/mdc800.c | 11 +---------- drivers/usb/image/microtek.c | 21 +++------------------ 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c index bc323a4c74bf..bd69f10c63f3 100644 --- a/drivers/usb/image/hpusbscsi.c +++ b/drivers/usb/image/hpusbscsi.c @@ -42,7 +42,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *altsetting = intf->altsetting; + struct usb_host_interface *altsetting = intf->cur_altsetting; struct hpusbscsi *new; int error = -ENOMEM; int i; diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 5d1ff8bbd012..f1b934c54088 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -431,7 +431,7 @@ static int mdc800_usb_probe (struct usb_interface *intf, err ("probe fails -> wrong Number of Configuration"); return -ENODEV; } - intf_desc = &intf->altsetting[0]; + intf_desc = intf->cur_altsetting; if ( ( intf_desc->desc.bInterfaceClass != 0xff ) @@ -469,13 +469,6 @@ static int mdc800_usb_probe (struct usb_interface *intf, } - usb_driver_claim_interface (&mdc800_usb_driver, intf, mdc800); - if (usb_set_interface (dev, intf_desc->desc.bInterfaceNumber, 0) < 0) - { - err ("MDC800 Configuration fails."); - return -ENODEV; - } - info ("Found Mustek MDC800 on USB."); down (&mdc800->io_lock); @@ -551,8 +544,6 @@ static void mdc800_usb_disconnect (struct usb_interface *intf) usb_unlink_urb (mdc800->write_urb); usb_unlink_urb (mdc800->download_urb); - usb_driver_release_interface (&mdc800_usb_driver, intf); - mdc800->dev=0; usb_set_intfdata(intf, NULL); } diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index e5f1a12dc2bb..19acf6221f97 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -693,7 +693,6 @@ static int mts_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { int i; - int result; int ep_out = -1; int ep_in_set[3]; /* this will break if we have more than three endpoints which is why we check */ @@ -703,7 +702,7 @@ static int mts_usb_probe(struct usb_interface *intf, struct vendor_product const* p; struct usb_device *dev = interface_to_usbdev (intf); - /* the altsettting 0 on the interface we're probing */ + /* the current altsetting on the interface we're probing */ struct usb_host_interface *altsetting; MTS_DEBUG_GOT_HERE(); @@ -724,8 +723,8 @@ static int mts_usb_probe(struct usb_interface *intf, MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", p->name ); - /* the altsettting 0 on the interface we're probing */ - altsetting = &(intf->altsetting[0]); + /* the current altsetting on the interface we're probing */ + altsetting = intf->cur_altsetting; /* Check if the config is sane */ @@ -766,20 +765,6 @@ static int mts_usb_probe(struct usb_interface *intf, MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); return -ENODEV; } - - result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0); - - MTS_DEBUG("usb_set_interface returned %d.\n",result); - switch( result ) - { - case 0: /* no error */ - break; - - default: - MTS_DEBUG( "unknown error %d from usb_set_interface\n", - (int)result ); - return -ENODEV; - } new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL); -- cgit v1.2.3 From ddd53405bdecb7778056cfbbbc9ca7229b8a5c7d Mon Sep 17 00:00:00 2001 From: Paulo Marques Date: Tue, 9 Mar 2004 22:50:30 -0800 Subject: [PATCH] USB: usblp.c (Was: usblp_write spins forever after an error) Paulo Marques wrote: > David Woodhouse wrote: > >> On Thu, 2004-03-04 at 12:33 +0000, Paulo Marques wrote: >> >>> Yes, unfortunately it did went into 2.6.4-rc1. However it is already >>> corrected in 2.6.4-rc2. Luckily it didn't went into any "non-rc" >>> official release. >>> >>> Please try 2.6.4-rc2, and check to see if the bug went away... >>> >> >> Seems to work; thanks. Does this need backporting to 2.4 too? >> > > > Unfortunately this isn't over yet. > > I got suspicious about this bug fix, because I *did* test my patch > before submitting it and the kernel that didn't work before, worked fine > with my patch. > > But now it seems that it is the other way around. After a few digging I > found out the problem: > > The application that I was testing with uses the usblp handle with > non-blocking I/O . > > So my patch does work for non-blocking I/O uses of the port, but wrecks > the normal blocking mode. > > I've already produced a version that works for both cases. I'll just > clean it up a bit and submit it to 2.4 and 2.6 kernels. Here it is. The patch is only one line for 2.6.4-rc2. (I also did a little formatting adjustment to better comply with CodingStyle) For the 2.4.26-pre1 kernel, I also backported the return codes correction patch from Oliver Neukum. The problem with the write function was that, in non-blocking mode, after submitting the first urb, the function would return with -EAGAIN, not reporting to the application that in fact it had already sent "transfer_length" bytes. This way the application would have to send the data *again* causing lots of errors. It did return the correct amount with my first patch, because the writecount was being updated on the end of the loop. However this was wrong for blocking I/O. The "transfer_length" local variable is still needed because if we used the transfer_buffer_length field from the urb, then on a second call to write, if the urb was still pending (in non-blocking mode), the write would return an incorrect amount of data written. Anyway, this time I tested it using blocking and non-blocking I/O and it works for both cases. Even better, this patch only changes the behaviour for non-blocking I/O, and keeps the same behaviour for the more usual blocking I/O (at least on kernel 2.6). --- drivers/usb/class/usblp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e6a453590615..0e269d78810d 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -610,8 +610,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t while (writecount < count) { if (!usblp->wcomplete) { barrier(); - if (file->f_flags & O_NONBLOCK) + if (file->f_flags & O_NONBLOCK) { + writecount += transfer_length; return writecount ? writecount : -EAGAIN; + } timeout = USBLP_WRITE_TIMEOUT; add_wait_queue(&usblp->wait, &wait); @@ -671,7 +673,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usblp->writeurb->transfer_buffer_length = transfer_length; - if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) { + if (copy_from_user(usblp->writeurb->transfer_buffer, + buffer + writecount, transfer_length)) { up(&usblp->sem); return writecount ? writecount : -EFAULT; } -- cgit v1.2.3 From 731ea3e983eff5a364bc2c81bc91d3c4eb6d8f51 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 11 Mar 2004 00:39:08 -0800 Subject: [PATCH] USB Gadget: add "gadget_chips.h" This adds standard gadget_is_*() calls. Gadget drivers using those calls can get rid of some inlined #ifdefs, and will also be able to do more "late binding" to their hardware. Define gadget_is_*() calls, to help do late binding to USB controllers. Current gadget drivers expect to know at compile time what hardware they'll bind to. That's not very friendly to a generic PDA distro, which might prefer to defer such choices to run time. These macros let drivers change that code from inlined #ifdefs (ugh) to normal C statements (looks much nicer), so making those "what hardware" policy choices at run time gets easier. --- drivers/usb/gadget/gadget_chips.h | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 drivers/usb/gadget/gadget_chips.h diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h new file mode 100644 index 000000000000..715cfa80eba2 --- /dev/null +++ b/drivers/usb/gadget/gadget_chips.h @@ -0,0 +1,57 @@ +/* + * USB device controllers have lots of quirks. Use these macros in + * gadget drivers or other code that needs to deal with them, and which + * autoconfigures instead of using early binding to the hardware. + * + * This could eventually work like the ARM mach_is_*() stuff, driven by + * some config file that gets updated as new hardware is supported. + * + * NOTE: some of these controller drivers may not be available yet. + */ +#ifdef CONFIG_USB_GADGET_NET2280 +#define gadget_is_net2280(g) !strcmp("net2280", (g)->name) +#else +#define gadget_is_net2280(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_PXA +#define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) +#else +#define gadget_is_pxa(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_GOKU +#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name) +#else +#define gadget_is_goku(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SUPERH +#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name) +#else +#define gadget_is_sh(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SA1100 +#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name) +#else +#define gadget_is_sa1100(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_MQ11XX +#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) +#else +#define gadget_is_mq11xx(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_OMAP +#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) +#else +#define gadget_is_omap(g) 0 +#endif + +// CONFIG_USB_GADGET_AT91RM9200 +// CONFIG_USB_GADGET_SX2 +// CONFIG_USB_GADGET_AU1X00 +// ... + -- cgit v1.2.3