diff -Nru a/CREDITS b/CREDITS --- a/CREDITS 2005-02-04 22:22:37 -08:00 +++ b/CREDITS 2005-02-04 22:22:37 -08:00 @@ -826,6 +826,11 @@ W: http://www.fsmlabs.com/linuxppcbk.html D: PowerPC +N: Daniel Drake +E: dsd@gentoo.org +D: USBAT02 CompactFlash support in usb-storage +S: UK + N: Oleg Drokin E: green@ccssu.crimea.ua W: http://www.ccssu.crimea.ua/~green diff -Nru a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt --- a/Documentation/usb/sn9c102.txt 2005-02-04 22:22:37 -08:00 +++ b/Documentation/usb/sn9c102.txt 2005-02-04 22:22:37 -08:00 @@ -210,8 +210,8 @@ SN9C10x bridge, while the other two control the sensor chip. "reg" and "i2c_reg" hold the values of the current register index where the following reading/writing operations are addressed at through "val" and "i2c_val". Their -use is not intended for end-users. Note that "i2c_reg" and "i2c_val" won't be -created if the sensor does not actually support the standard I2C protocol or +use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not +be created if the sensor does not actually support the standard I2C protocol or its registers are not 8-bit long. Also, remember that you must be logged in as root before writing to them. @@ -341,15 +341,8 @@ All the available control settings of each image sensor are supported through the V4L2 interface. -If you think your camera is based on the above hardware and is not actually -listed in the above table, you may try to add the specific USB VendorID and -ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h"; -then compile, load the module again and look at the kernel output. -If this works, please send an email to the author reporting the kernel -messages, so that a new entry in the list of supported devices can be added. - Donations of new models for further testing and support would be much -appreciated. Non-available hardware won't be supported by the author of this +appreciated. Non-available hardware will not be supported by the author of this driver. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS 2005-02-04 22:22:37 -08:00 +++ b/MAINTAINERS 2005-02-04 22:22:37 -08:00 @@ -2028,6 +2028,12 @@ W: http://www.winischhofer.net/linuxsisvga.shtml S: Maintained +SIS USB2VGA DRIVER +P: Thomas Winischhofer +M: thomas@winischhofer.net +W: http://www.winischhofer.at/linuxsisusbvga.shtml +S: Maintained + SMSC47M1 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- a/drivers/block/ub.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/block/ub.c 2005-02-04 22:22:37 -08:00 @@ -300,6 +300,11 @@ /* */ +static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq); +static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq); +static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq); static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_end_rq(struct request *rq, int uptodate); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -591,40 +596,73 @@ * The request function is our main entry point */ -static inline int ub_bd_rq_fn_1(request_queue_t *q) +static void ub_bd_rq_fn(request_queue_t *q) { -#if 0 - int writing = 0, pci_dir, i, n_elem; - u32 tmp; - unsigned int msg_size; -#endif struct ub_dev *sc = q->queuedata; struct request *rq; -#if 0 /* We use rq->buffer for now */ - struct scatterlist *sg; - int n_elem; -#endif + + while ((rq = elv_next_request(q)) != NULL) { + if (ub_bd_rq_fn_1(sc, rq) != 0) { + blk_stop_queue(q); + break; + } + } +} + +static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq) +{ struct ub_scsi_cmd *cmd; - int ub_dir; - unsigned int block, nblks; int rc; - if ((rq = elv_next_request(q)) == NULL) - return 1; - if (atomic_read(&sc->poison) || sc->changed) { blkdev_dequeue_request(rq); ub_end_rq(rq, 0); return 0; } - if ((cmd = ub_get_cmd(sc)) == NULL) { - blk_stop_queue(q); - return 1; - } + if ((cmd = ub_get_cmd(sc)) == NULL) + return -1; + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); blkdev_dequeue_request(rq); + if (blk_pc_request(rq)) { + rc = ub_cmd_build_packet(sc, cmd, rq); + } else { + rc = ub_cmd_build_block(sc, cmd, rq); + } + if (rc != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(sc->disk->queue); + return 0; + } + + cmd->state = UB_CMDST_INIT; + cmd->done = ub_rw_cmd_done; + cmd->back = rq; + + cmd->tag = sc->tagcnt++; + if ((rc = ub_submit_scsi(sc, cmd)) != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(sc->disk->queue); + return 0; + } + + return 0; +} + +static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq) +{ + int ub_dir; +#if 0 /* We use rq->buffer for now */ + struct scatterlist *sg; + int n_elem; +#endif + unsigned int block, nblks; + if (rq_data_dir(rq) == WRITE) ub_dir = UB_DIR_WRITE; else @@ -652,6 +690,7 @@ return 0; } #endif + /* * XXX Unfortunately, this check does not work. It is quite possible * to get bogus non-null rq->buffer if you allow sg by mistake. @@ -663,13 +702,12 @@ */ static int do_print = 1; if (do_print) { - printk(KERN_WARNING "%s: unmapped request\n", sc->name); + printk(KERN_WARNING "%s: unmapped block request" + " flags 0x%lx sectors %lu\n", + sc->name, rq->flags, rq->nr_sectors); do_print = 0; } - ub_put_cmd(sc, cmd); - ub_end_rq(rq, 0); - blk_start_queue(q); - return 0; + return -1; } /* @@ -681,7 +719,6 @@ block = rq->sector >> sc->capacity.bshift; nblks = rq->nr_sectors >> sc->capacity.bshift; - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ cmd->cdb[2] = block >> 24; @@ -691,27 +728,44 @@ cmd->cdb[7] = nblks >> 8; cmd->cdb[8] = nblks; cmd->cdb_len = 10; + cmd->dir = ub_dir; - cmd->state = UB_CMDST_INIT; cmd->data = rq->buffer; cmd->len = rq->nr_sectors * 512; - cmd->done = ub_rw_cmd_done; - cmd->back = rq; - - cmd->tag = sc->tagcnt++; - if ((rc = ub_submit_scsi(sc, cmd)) != 0) { - ub_put_cmd(sc, cmd); - ub_end_rq(rq, 0); - blk_start_queue(q); - return 0; - } return 0; } -static void ub_bd_rq_fn(request_queue_t *q) +static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq) { - do { } while (ub_bd_rq_fn_1(q) == 0); + + if (rq->data_len != 0 && rq->data == NULL) { + static int do_print = 1; + if (do_print) { + printk(KERN_WARNING "%s: unmapped packet request" + " flags 0x%lx length %d\n", + sc->name, rq->flags, rq->data_len); + do_print = 0; + } + return -1; + } + + memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); + cmd->cdb_len = rq->cmd_len; + + if (rq->data_len == 0) { + cmd->dir = UB_DIR_NONE; + } else { + if (rq_data_dir(rq) == WRITE) + cmd->dir = UB_DIR_WRITE; + else + cmd->dir = UB_DIR_READ; + } + cmd->data = rq->data; + cmd->len = rq->data_len; + + return 0; } static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) @@ -721,6 +775,12 @@ request_queue_t *q = disk->queue; int uptodate; + if (blk_pc_request(rq)) { + /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */ + memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE); + rq->sense_len = UB_SENSE_SIZE; + } + if (cmd->error == 0) uptodate = 1; else @@ -779,6 +839,17 @@ bcb = &sc->work_bcb; + /* + * ``If the allocation length is eighteen or greater, and a device + * server returns less than eithteen bytes of data, the application + * client should assume that the bytes not transferred would have been + * zeroes had the device server returned those bytes.'' + * + * We zero sense for all commands so that when a packet request + * fails it does not return a stale sense. + */ + memset(&sc->top_sense, 0, UB_SENSE_SIZE); + /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->Tag = cmd->tag; /* Endianness is not important */ @@ -1222,14 +1293,6 @@ goto error; } - /* - * ``If the allocation length is eighteen or greater, and a device - * server returns less than eithteen bytes of data, the application - * client should assume that the bytes not transferred would have been - * zeroes had the device server returned those bytes.'' - */ - memset(&sc->top_sense, 0, UB_SENSE_SIZE); - scmd = &sc->top_rqs_cmd; scmd->cdb[0] = REQUEST_SENSE; scmd->cdb[4] = UB_SENSE_SIZE; @@ -1495,30 +1558,10 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { -// void __user *usermem = (void *) arg; -// struct carm_port *port = ino->i_bdev->bd_disk->private_data; -// struct hd_geometry geom; - -#if 0 - switch (cmd) { - case HDIO_GETGEO: - if (usermem == NULL) // XXX Bizzare. Why? - return -EINVAL; - - geom.heads = (u8) port->dev_geom_head; - geom.sectors = (u8) port->dev_geom_sect; - geom.cylinders = port->dev_geom_cyl; - geom.start = get_start_sect(ino->i_bdev); - - if (copy_to_user(usermem, &geom, sizeof(geom))) - return -EFAULT; - return 0; - - default: ; - } -#endif + struct gendisk *disk = inode->i_bdev->bd_disk; + void __user *usermem = (void __user *) arg; - return -ENOTTY; + return scsi_cmd_ioctl(filp, disk, cmd, usermem); } /* diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig --- a/drivers/usb/Kconfig 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/Kconfig 2005-02-04 22:22:37 -08:00 @@ -56,6 +56,8 @@ source "drivers/usb/net/Kconfig" +source "drivers/usb/mon/Kconfig" + comment "USB port drivers" depends on USB diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/Makefile 2005-02-04 22:22:37 -08:00 @@ -6,6 +6,8 @@ obj-$(CONFIG_USB) += core/ +obj-$(CONFIG_USB_MON) += mon/ + obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/class/cdc-acm.c 2005-02-04 22:22:37 -08:00 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -97,9 +98,12 @@ /* devices aren't required to support these requests. * the cdc acm descriptor tells whether they do... */ -#define acm_set_control(acm, control) acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0) -#define acm_set_line(acm, line) acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line)) -#define acm_send_break(acm, ms) acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0) +#define acm_set_control(acm, control) \ + acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) +#define acm_set_line(acm, line) \ + acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) +#define acm_send_break(acm, ms) \ + acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) /* * Interrupt handlers for various ACM device responses @@ -109,7 +113,7 @@ static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs) { struct acm *acm = urb->context; - struct usb_ctrlrequest *dr = urb->transfer_buffer; + struct usb_cdc_notification *dr = urb->transfer_buffer; unsigned char *data; int newctrl; int status; @@ -133,14 +137,14 @@ goto exit; data = (unsigned char *)(dr + 1); - switch (dr->bRequest) { + switch (dr->bNotificationType) { - case ACM_IRQ_NETWORK: + case USB_CDC_NOTIFY_NETWORK_CONNECTION: dbg("%s network", dr->wValue ? "connected to" : "disconnected from"); break; - case ACM_IRQ_LINE_STATE: + case USB_CDC_NOTIFY_SERIAL_STATE: newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); @@ -160,8 +164,9 @@ break; default: - dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d", - dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]); + dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", + dr->bNotificationType, dr->wIndex, + dr->wLength, data[0], data[1]); break; } exit: @@ -485,32 +490,34 @@ { struct acm *acm = tty->driver_data; struct termios *termios = tty->termios; - struct acm_line newline; + struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; if (!ACM_READY(acm)) return; - newline.speed = cpu_to_le32p(acm_tty_speed + + newline.dwDTERate = cpu_to_le32p(acm_tty_speed + (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); - newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0; - newline.parity = termios->c_cflag & PARENB ? + newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; + newline.bParityType = termios->c_cflag & PARENB ? (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; - newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; + newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; acm->clocal = ((termios->c_cflag & CLOCAL) != 0); - if (!newline.speed) { - newline.speed = acm->line.speed; + if (!newline.dwDTERate) { + newline.dwDTERate = acm->line.dwDTERate; newctrl &= ~ACM_CTRL_DTR; } else newctrl |= ACM_CTRL_DTR; if (newctrl != acm->ctrlout) acm_set_control(acm, acm->ctrlout = newctrl); - if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) { - memcpy(&acm->line, &newline, sizeof(struct acm_line)); - dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits); + if (memcmp(&acm->line, &newline, sizeof newline)) { + memcpy(&acm->line, &newline, sizeof newline); + dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate), + newline.bCharFormat, newline.bParityType, + newline.bDataBits); acm_set_line(acm, &acm->line); } } @@ -522,7 +529,7 @@ static int acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { - struct union_desc *union_header = NULL; + struct usb_cdc_union_desc *union_header = NULL; char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; @@ -573,21 +580,22 @@ } switch (buffer [2]) { - case CDC_UNION_TYPE: /* we've found it */ + case USB_CDC_UNION_TYPE: /* we've found it */ if (union_header) { err("More than one union descriptor, skipping ..."); goto next_desc; } - union_header = (struct union_desc *)buffer; + union_header = (struct usb_cdc_union_desc *) + buffer; break; - case CDC_COUNTRY_TYPE: /* maybe somehow export */ + case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */ break; /* for now we ignore it */ - case CDC_HEADER_TYPE: /* maybe check version */ + case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ - case CDC_AC_MANAGEMENT_TYPE: + case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; - case CDC_CALL_MANAGEMENT_TYPE: + case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ((call_management_function & 3) != 3) @@ -750,8 +758,8 @@ acm_set_control(acm, acm->ctrlout); - acm->line.speed = cpu_to_le32(9600); - acm->line.databits = 8; + acm->line.dwDTERate = cpu_to_le32(9600); + acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); @@ -831,14 +839,20 @@ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, /* control interfaces with various AT-command sets */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 1) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 2) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 3) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 4) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 5) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 6) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_V25TER) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_PCCA101) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_GSM) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_3G ) }, + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_CDMA) }, - /* NOTE: COMM/2/0xff is likely MSFT RNDIS ... NOT a modem!! */ + /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ { } }; diff -Nru a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h --- a/drivers/usb/class/cdc-acm.h 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/class/cdc-acm.h 2005-02-04 22:22:37 -08:00 @@ -27,24 +27,6 @@ #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) -#define ACM_REQ_COMMAND 0x00 -#define ACM_REQ_RESPONSE 0x01 -#define ACM_REQ_SET_FEATURE 0x02 -#define ACM_REQ_GET_FEATURE 0x03 -#define ACM_REQ_CLEAR_FEATURE 0x04 - -#define ACM_REQ_SET_LINE 0x20 -#define ACM_REQ_GET_LINE 0x21 -#define ACM_REQ_SET_CONTROL 0x22 -#define ACM_REQ_SEND_BREAK 0x23 - -/* - * IRQs. - */ - -#define ACM_IRQ_NETWORK 0x00 -#define ACM_IRQ_LINE_STATE 0x20 - /* * Output control lines. */ @@ -66,17 +48,6 @@ #define ACM_CTRL_OVERRUN 0x40 /* - * Line speed and caracter encoding. - */ - -struct acm_line { - __le32 speed; - __u8 stopbits; - __u8 parity; - __u8 databits; -} __attribute__ ((packed)); - -/* * Internal driver structures. */ @@ -88,7 +59,7 @@ struct urb *ctrlurb, *readurb, *writeurb; /* urbs */ u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */ dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */ - struct acm_line line; /* line coding (bits, stop, parity) */ + struct usb_cdc_line_coding line; /* bits, stop, parity */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct bh; /* rx processing */ spinlock_t throttle_lock; /* synchronize throtteling and read callback */ @@ -104,24 +75,6 @@ unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ }; - -/* "Union Functional Descriptor" from CDC spec 5.2.3.X */ -struct union_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u8 bMasterInterface0; - u8 bSlaveInterface0; - /* ... and there could be other slave interfaces */ -} __attribute__ ((packed)); - -/* class specific descriptor types */ -#define CDC_HEADER_TYPE 0x00 -#define CDC_CALL_MANAGEMENT_TYPE 0x01 -#define CDC_AC_MANAGEMENT_TYPE 0x02 -#define CDC_UNION_TYPE 0x06 -#define CDC_COUNTRY_TYPE 0x07 #define CDC_DATA_INTERFACE_TYPE 0x0a diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/core/hcd.c 2005-02-04 22:22:37 -08:00 @@ -45,6 +45,7 @@ #include "usb.h" #include "hcd.h" +#include "hub.h" // #define USB_BANDWIDTH_MESSAGES @@ -86,6 +87,7 @@ /* host controllers we manage */ LIST_HEAD (usb_bus_list); +EXPORT_SYMBOL_GPL (usb_bus_list); /* used when allocating bus numbers */ #define USB_MAXBUS 64 @@ -96,6 +98,7 @@ /* used when updating list of hcds */ DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ +EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used when updating hcd data */ static DEFINE_SPINLOCK(hcd_data_lock); @@ -271,6 +274,10 @@ *utf++ = *s++; *utf++ = 0; } + if (utfmax > 0) { + *utf = *s; + ++retval; + } return retval; } @@ -295,30 +302,40 @@ // language ids if (id == 0) { - *data++ = 4; *data++ = 3; /* 4 bytes string data */ - *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */ - return 4; + buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ + buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ + len = min (len, 4); + memcpy (data, buf, len); + return len; // serial number } else if (id == 1) { - strcpy (buf, hcd->self.bus_name); + strlcpy (buf, hcd->self.bus_name, sizeof buf); // product description } else if (id == 2) { - strcpy (buf, hcd->product_desc); + strlcpy (buf, hcd->product_desc, sizeof buf); // id 3 == vendor description } else if (id == 3) { - sprintf (buf, "%s %s %s", system_utsname.sysname, + snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname, system_utsname.release, hcd->driver->description); // unsupported IDs --> "protocol stall" } else - return 0; + return -EPIPE; - data [0] = 2 * (strlen (buf) + 1); - data [1] = 3; /* type == string */ - return 2 + ascii2utf (buf, data + 2, len - 2); + switch (len) { /* All cases fall through */ + default: + len = 2 + ascii2utf (buf, data + 2, len - 2); + case 2: + data [1] = 3; /* type == string */ + case 1: + data [0] = 2 * (strlen (buf) + 1); + case 0: + ; /* Compiler wants a statement here */ + } + return len; } @@ -327,11 +344,14 @@ { struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; - const u8 *bufp = NULL; u8 *ubuf = urb->transfer_buffer; + u8 tbuf [sizeof (struct usb_hub_descriptor)]; + const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; unsigned long flags; + int status = 0; + int n; cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; @@ -342,17 +362,16 @@ if (wLength > urb->transfer_buffer_length) goto error; - /* set up for success */ - urb->status = 0; - urb->actual_length = wLength; + urb->actual_length = 0; switch (typeReq) { /* DEVICE REQUESTS */ case DeviceRequest | USB_REQ_GET_STATUS: - ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) + tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); - ubuf [1] = 0; + tbuf [1] = 0; + len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (wValue == USB_DEVICE_REMOTE_WAKEUP) @@ -367,7 +386,8 @@ goto error; break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - ubuf [0] = 1; + tbuf [0] = 1; + len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: break; @@ -394,16 +414,18 @@ patch_wakeup = 1; break; case USB_DT_STRING << 8: - urb->actual_length = rh_string ( - wValue & 0xff, hcd, - ubuf, wLength); + n = rh_string (wValue & 0xff, hcd, ubuf, wLength); + if (n < 0) + goto error; + urb->actual_length = n; break; default: goto error; } break; case DeviceRequest | USB_REQ_GET_INTERFACE: - ubuf [0] = 0; + tbuf [0] = 0; + len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_INTERFACE: break; @@ -419,8 +441,9 @@ case EndpointRequest | USB_REQ_GET_STATUS: // ENDPOINT_HALT flag - ubuf [0] = 0; - ubuf [1] = 0; + tbuf [0] = 0; + tbuf [1] = 0; + len = 2; /* FALLTHROUGH */ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_SET_FEATURE: @@ -432,19 +455,30 @@ default: /* non-generic request */ if (HCD_IS_SUSPENDED (hcd->state)) - urb->status = -EAGAIN; - else - urb->status = hcd->driver->hub_control (hcd, + status = -EAGAIN; + else { + switch (typeReq) { + case GetHubStatus: + case GetPortStatus: + len = 4; + break; + case GetHubDescriptor: + len = sizeof (struct usb_hub_descriptor); + break; + } + status = hcd->driver->hub_control (hcd, typeReq, wValue, wIndex, - ubuf, wLength); + tbuf, wLength); + } break; error: /* "protocol stall" on error */ - urb->status = -EPIPE; + status = -EPIPE; } - if (urb->status) { - urb->actual_length = 0; - if (urb->status != -EPIPE) { + + if (status) { + len = 0; + if (status != -EPIPE) { dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x " "idx=0x%x len=%d ==> %d\n", @@ -452,7 +486,7 @@ wLength, urb->status); } } - if (bufp) { + if (len) { if (urb->transfer_buffer_length < len) len = urb->transfer_buffer_length; urb->actual_length = len; @@ -460,13 +494,19 @@ memcpy (ubuf, bufp, len); /* report whether RH hardware supports remote wakeup */ - if (patch_wakeup) + if (patch_wakeup && + len > offsetof (struct usb_config_descriptor, + bmAttributes)) ((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } /* any errors get returned through the urb completion */ local_irq_save (flags); + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock (&urb->lock); usb_hcd_giveback_urb (hcd, urb, NULL); local_irq_restore (flags); return 0; @@ -746,6 +786,7 @@ up (&usb_bus_list_lock); usbfs_add_bus (bus); + usbmon_notify_bus_add (bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); return 0; @@ -773,6 +814,7 @@ list_del (&bus->bus_list); up (&usb_bus_list_lock); + usbmon_notify_bus_remove (bus); usbfs_remove_bus (bus); clear_bit (bus->busnum, busmap.busmap); @@ -1058,9 +1100,7 @@ * as simple as possible. */ - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) - // It would catch submission paths for all urbs. + usbmon_urb_submit(&hcd->self, urb); /* * Atomically queue the urb, first to our records, then to the HCD. @@ -1087,6 +1127,7 @@ spin_unlock_irqrestore (&hcd_data_lock, flags); if (status) { INIT_LIST_HEAD (&urb->urb_list); + usbmon_urb_submit_error(&hcd->self, urb, status); return status; } @@ -1103,8 +1144,6 @@ * valid and usb_buffer_{sync,unmap}() not be needed, since * they could clobber root hub response data. */ - urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); status = rh_urb_enqueue (hcd, urb); goto done; } @@ -1139,6 +1178,7 @@ if (urb->reject) wake_up (&usb_kill_urb_queue); usb_put_urb (urb); + usbmon_urb_submit_error(&hcd->self, urb, status); } return status; } @@ -1461,14 +1501,13 @@ */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { - urb_unlink (urb); + int at_root_hub; - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) - // It would catch exit/unlink paths for all urbs. + at_root_hub = (urb->dev == hcd->self.root_hub); + urb_unlink (urb); /* lower level hcd code should use *_dma exclusively */ - if (hcd->self.controller->dma_mask) { + if (hcd->self.controller->dma_mask && !at_root_hub) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, @@ -1484,6 +1523,7 @@ : DMA_TO_DEVICE); } + usbmon_urb_complete (&hcd->self, urb); /* pass ownership to the completion handler */ urb->complete (urb, regs); atomic_dec (&urb->use_count); @@ -1591,3 +1631,43 @@ usb_bus_put(&hcd->self); } EXPORT_SYMBOL (usb_put_hcd); + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) + +struct usb_mon_operations *mon_ops; + +/* + * The registration is unlocked. + * We do it this way because we do not want to lock in hot paths. + * + * Notice that the code is minimally error-proof. Because usbmon needs + * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. + */ + +int usb_mon_register (struct usb_mon_operations *ops) +{ + + if (mon_ops) + return -EBUSY; + + mon_ops = ops; + mb(); + return 0; +} +EXPORT_SYMBOL_GPL (usb_mon_register); + +void usb_mon_deregister (void) +{ + + if (mon_ops == NULL) { + printk(KERN_ERR "USB: monitor was not registered\n"); + return; + } + mon_ops = NULL; + mb(); +} +EXPORT_SYMBOL_GPL (usb_mon_deregister); + +#endif /* CONFIG_USB_MON */ diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/core/hcd.h 2005-02-04 22:22:37 -08:00 @@ -411,6 +411,66 @@ /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) + +struct usb_mon_operations { + void (*urb_submit)(struct usb_bus *bus, struct urb *urb); + void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ + void (*bus_add)(struct usb_bus *bus); + void (*bus_remove)(struct usb_bus *bus); +}; + +extern struct usb_mon_operations *mon_ops; + +static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) +{ + if (bus->monitored) + (*mon_ops->urb_submit)(bus, urb); +} + +static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, + int error) +{ + if (bus->monitored) + (*mon_ops->urb_submit_error)(bus, urb, error); +} + +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +{ + if (bus->monitored) + (*mon_ops->urb_complete)(bus, urb); +} + +static inline void usbmon_notify_bus_add(struct usb_bus *bus) +{ + if (mon_ops) + (*mon_ops->bus_add)(bus); +} + +static inline void usbmon_notify_bus_remove(struct usb_bus *bus) +{ + if (mon_ops) + (*mon_ops->bus_remove)(bus); +} + +int usb_mon_register(struct usb_mon_operations *ops); +void usb_mon_deregister(void); + +#else + +static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, + int error) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_notify_bus_add(struct usb_bus *bus) {} +static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {} + +#endif /* CONFIG_USB_MON */ + +/*-------------------------------------------------------------------------*/ + /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ // bleech -- resurfaced in 2.4.11 or 2.4.12 #define bitmap DeviceRemovable diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/core/hub.c 2005-02-04 22:22:37 -08:00 @@ -74,7 +74,7 @@ MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -static int use_both_schemes = 0; +static int use_both_schemes = 1; module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " @@ -459,6 +459,7 @@ int status; hub->quiescing = 0; + hub->activating = 1; status = usb_submit_urb(hub->urb, GFP_NOIO); if (status < 0) dev_err(hub->intfdev, "activate --> %d\n", status); @@ -466,7 +467,6 @@ schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); /* scan all ports ASAP */ - hub->event_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 1; kick_khubd(hub); } @@ -689,7 +689,6 @@ hub->indicator [0] = INDICATOR_CYCLE; hub_power_on(hub); - hub->change_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 2; hub_activate(hub); return 0; @@ -1235,10 +1234,10 @@ */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { static int __usb_suspend_device (struct usb_device *, - int port1, u32 state); + int port1, pm_message_t state); err = __usb_suspend_device(udev, udev->bus->otg_port, - PM_SUSPEND_MEM); + PMSG_SUSPEND); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } @@ -1523,7 +1522,7 @@ * Linux (2.6) currently has NO mechanisms to initiate that: no khubd * timer, no SRP, no requests through sysfs. */ -int __usb_suspend_device (struct usb_device *udev, int port1, u32 state) +int __usb_suspend_device (struct usb_device *udev, int port1, pm_message_t state) { int status; @@ -1621,7 +1620,7 @@ /** * usb_suspend_device - suspend a usb device * @udev: device that's no longer in active use - * @state: PM_SUSPEND_MEM to suspend + * @state: PMSG_SUSPEND to suspend * Context: must be able to sleep; device not locked * * Suspends a USB device that isn't in active use, conserving power. @@ -1670,7 +1669,7 @@ usb_set_device_state(udev, udev->actconfig ? USB_STATE_CONFIGURED : USB_STATE_ADDRESS); - udev->dev.power.power_state = PM_SUSPEND_ON; + udev->dev.power.power_state = PMSG_ON; /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, @@ -1871,7 +1870,7 @@ return status; } -static int hub_suspend(struct usb_interface *intf, u32 state) +static int hub_suspend(struct usb_interface *intf, pm_message_t state) { struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; @@ -1943,7 +1942,7 @@ } up(&udev->serialize); } - intf->dev.power.power_state = PM_SUSPEND_ON; + intf->dev.power.power_state = PMSG_ON; hub_activate(hub); return 0; @@ -2178,24 +2177,35 @@ retval = -ENOMEM; continue; } - buf->bMaxPacketSize0 = 0; /* Use a short timeout the first time through, * so that recalcitrant full-speed devices with * 8- or 16-byte ep0-maxpackets won't slow things * down tremendously by NAKing the unexpectedly - * early status stage. Also, retry on length 0 - * or stall; some devices are flakey. + * early status stage. Also, retry on all errors; + * some devices are flakey. */ for (j = 0; j < 3; ++j) { + buf->bMaxPacketSize0 = 0; r = usb_control_msg(udev, usb_rcvaddr0pipe(), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 0, buf, GET_DESCRIPTOR_BUFSIZE, (i ? HZ * USB_CTRL_GET_TIMEOUT : HZ)); - if (r == 0 || r == -EPIPE) - continue; - if (r < 0) + switch (buf->bMaxPacketSize0) { + case 8: case 16: case 32: case 64: + if (buf->bDescriptorType == + USB_DT_DEVICE) { + r = 0; + break; + } + /* FALL THROUGH */ + default: + if (r == 0) + r = -EPROTO; + break; + } + if (r == 0) break; } udev->descriptor.bMaxPacketSize0 = @@ -2211,10 +2221,7 @@ retval = -ENODEV; goto fail; } - switch (udev->descriptor.bMaxPacketSize0) { - case 64: case 32: case 16: case 8: - break; - default: + if (r) { dev_err(&udev->dev, "device descriptor " "read/%s, error %d\n", "64", r); @@ -2627,7 +2634,7 @@ for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { connect_change = test_bit(i, hub->change_bits); if (!test_and_clear_bit(i, hub->event_bits) && - !connect_change) + !connect_change && !hub->activating) continue; ret = hub_port_status(hub, i, @@ -2635,6 +2642,11 @@ if (ret < 0) continue; + if (hub->activating && !hdev->children[i-1] && + (portstatus & + USB_PORT_STAT_CONNECTION)) + connect_change = 1; + if (portchange & USB_PORT_STAT_C_CONNECTION) { clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); @@ -2724,6 +2736,8 @@ hub_power_on(hub); } } + + hub->activating = 0; loop: usb_unlock_device(hdev); diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/core/hub.h 2005-02-04 22:22:37 -08:00 @@ -215,6 +215,7 @@ u8 power_budget; /* in 2mA units; or zero */ unsigned quiescing:1; + unsigned activating:1; unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/Kconfig 2005-02-04 22:22:37 -08:00 @@ -87,10 +87,10 @@ default USB_GADGET config USB_GADGET_PXA2XX - boolean "PXA 2xx or IXP 4xx" - depends on ARCH_PXA || ARCH_IXP4XX + boolean "PXA 25x or IXP 4xx" + depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX help - Intel's PXA 2xx series XScale ARM-5TE processors include + Intel's PXA 25x series XScale ARM-5TE processors include an integrated full speed USB 1.1 device controller. The controller in the IXP 4xx series is register-compatible. @@ -194,7 +194,7 @@ config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP - select ISP1301_OMAP if MACH_OMAP_H2 + select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/ether.c 2005-02-04 22:22:37 -08:00 @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -432,8 +433,8 @@ /* status endpoint is optional; this may be patched later */ .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = 6, /* ethernet control model */ - .bInterfaceProtocol = 0, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, .iInterface = STRING_CONTROL, }; #endif @@ -447,46 +448,26 @@ .bInterfaceNumber = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = 2, /* abstract control model */ - .bInterfaceProtocol = 0xff, /* vendor specific */ + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, .iInterface = STRING_RNDIS_CONTROL, }; #endif #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) -/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ -struct header_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u16 bcdCDC; -} __attribute__ ((packed)); - -static const struct header_desc header_desc = { +static const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = 0, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = __constant_cpu_to_le16 (0x0110), }; -/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ -struct union_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u8 bMasterInterface0; - u8 bSlaveInterface0; - /* ... and there could be other slave interfaces */ -} __attribute__ ((packed)); - -static const struct union_desc union_desc = { +static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = 6, + .bDescriptorSubType = USB_CDC_UNION_TYPE, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of DATA interface */ @@ -496,64 +477,31 @@ #ifdef CONFIG_USB_ETH_RNDIS -/* "Call Management Descriptor" from CDC spec 5.2.3.3 */ -struct call_mgmt_descriptor { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u8 bmCapabilities; - u8 bDataInterface; -} __attribute__ ((packed)); - -static const struct call_mgmt_descriptor call_mgmt_descriptor = { +static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bLength = sizeof call_mgmt_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = 0x01, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, .bmCapabilities = 0x00, .bDataInterface = 0x01, }; - -/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.4 */ -struct acm_descriptor { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u8 bmCapabilities; -} __attribute__ ((packed)); - -static struct acm_descriptor acm_descriptor = { +static struct usb_cdc_acm_descriptor acm_descriptor = { .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = 0x02, + .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0X00, + .bmCapabilities = 0x00, }; #endif #ifdef DEV_CONFIG_CDC -/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ -struct ether_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - - u8 iMACAddress; - u32 bmEthernetStatistics; - u16 wMaxSegmentSize; - u16 wNumberMCFilters; - u8 bNumberPowerFilters; -} __attribute__ ((packed)); - -static const struct ether_desc ether_desc = { +static const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = 0x0f, + .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, /* this descriptor actually adds value, surprise! */ .iMACAddress = STRING_ETHADDR, @@ -1242,47 +1190,30 @@ /*-------------------------------------------------------------------------*/ -/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications - * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS - * and RNDIS also defines its own bit-incompatible notifications - */ -#define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */ -#define CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 /* optional; 6.3.2 */ -#define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */ - #ifdef DEV_CONFIG_CDC -struct cdc_notification { - u8 bmRequestType; - u8 bNotificationType; - u16 wValue; - u16 wIndex; - u16 wLength; - - /* SPEED_CHANGE data looks like this */ - u32 data [2]; -}; - static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) { - struct cdc_notification *event = req->buf; - int value = req->status; - struct eth_dev *dev = ep->driver_data; + struct usb_cdc_notification *event = req->buf; + int value = req->status; + struct eth_dev *dev = ep->driver_data; /* issue the second notification if host reads the first */ - if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION + if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION && value == 0) { + __le32 *data = req->buf + sizeof *event; + event->bmRequestType = 0xA1; - event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE; + event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE; event->wValue = __constant_cpu_to_le16 (0); event->wIndex = __constant_cpu_to_le16 (1); event->wLength = __constant_cpu_to_le16 (8); /* SPEED_CHANGE data is up/down speeds in bits/sec */ - event->data [0] = event->data [1] = + data [0] = data [1] = cpu_to_le32( (dev->gadget->speed == USB_SPEED_HIGH) ? (13 * 512 * 8 * 1000 * 8) - : (19 * 64 * 1 * 1000 * 8); + : (19 * 64 * 1 * 1000 * 8)); req->length = 16; value = usb_ep_queue (ep, req, GFP_ATOMIC); @@ -1300,9 +1231,9 @@ static void issue_start_status (struct eth_dev *dev) { - struct usb_request *req; - struct cdc_notification *event; - int value; + struct usb_request *req; + struct usb_cdc_notification *event; + int value; DEBUG (dev, "%s, flush old status first\n", __FUNCTION__); @@ -1336,7 +1267,7 @@ */ event = req->buf; event->bmRequestType = 0xA1; - event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION; + event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION; event->wValue = __constant_cpu_to_le16 (1); /* connected */ event->wIndex = __constant_cpu_to_le16 (1); event->wLength = 0; @@ -1364,26 +1295,6 @@ req->status, req->actual, req->length); } -/* see section 3.8.2 table 10 of the CDC spec for more ethernet - * requests, mostly for filters (multicast, pm) and statistics - * section 3.6.2.1 table 4 has ACM requests; RNDIS requires the - * encapsulated command mechanism. - */ -#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 /* optional */ -#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */ -#define CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 /* optional */ -#define CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 /* optional */ -#define CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 /* optional */ -#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ -#define CDC_GET_ETHERNET_STATISTIC 0x44 /* optional */ - -/* table 62; bits in cdc_filter */ -#define CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) -#define CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ -#define CDC_PACKET_TYPE_DIRECTED (1 << 2) -#define CDC_PACKET_TYPE_BROADCAST (1 << 3) -#define CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ - #ifdef CONFIG_USB_ETH_RNDIS static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req) @@ -1393,7 +1304,7 @@ "rndis response complete --> %d, %d/%d\n", req->status, req->actual, req->length); - /* done sending after CDC_GET_ENCAPSULATED_RESPONSE */ + /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */ } static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) @@ -1401,7 +1312,7 @@ struct eth_dev *dev = ep->driver_data; int status; - /* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */ + /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ spin_lock(&dev->lock); status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); if (status < 0) @@ -1426,6 +1337,9 @@ struct eth_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; + u16 wIndex = ctrl->wIndex; + u16 wValue = ctrl->wValue; + u16 wLength = ctrl->wLength; /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. @@ -1436,17 +1350,17 @@ case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; - switch (ctrl->wValue >> 8) { + switch (wValue >> 8) { case USB_DT_DEVICE: - value = min (ctrl->wLength, (u16) sizeof device_desc); + value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; - value = min (ctrl->wLength, (u16) sizeof dev_qualifier); + value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; @@ -1457,18 +1371,18 @@ #endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, - ctrl->wValue >> 8, - ctrl->wValue & 0xff, + wValue >> 8, + wValue & 0xff, gadget->is_otg); if (value >= 0) - value = min (ctrl->wLength, (u16) value); + value = min (wLength, (u16) value); break; case USB_DT_STRING: value = usb_gadget_get_string (&stringtab, - ctrl->wValue & 0xff, req->buf); + wValue & 0xff, req->buf); if (value >= 0) - value = min (ctrl->wLength, (u16) value); + value = min (wLength, (u16) value); break; } break; @@ -1481,22 +1395,22 @@ else if (gadget->a_alt_hnp_support) DEBUG (dev, "HNP needs a different root port\n"); spin_lock (&dev->lock); - value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); + value = eth_set_config (dev, wValue, GFP_ATOMIC); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *)req->buf = dev->config; - value = min (ctrl->wLength, (u16) 1); + value = min (wLength, (u16) 1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->config - || ctrl->wIndex > 1) + || wIndex > 1) break; - if (!dev->cdc && ctrl->wIndex != 0) + if (!dev->cdc && wIndex != 0) break; spin_lock (&dev->lock); @@ -1510,9 +1424,9 @@ } #ifdef DEV_CONFIG_CDC - switch (ctrl->wIndex) { + switch (wIndex) { case 0: /* control/master intf */ - if (ctrl->wValue != 0) + if (wValue != 0) break; if (dev->status_ep) { usb_ep_disable (dev->status_ep); @@ -1521,7 +1435,7 @@ value = 0; break; case 1: /* data intf */ - if (ctrl->wValue > 1) + if (wValue > 1) break; usb_ep_disable (dev->in_ep); usb_ep_disable (dev->out_ep); @@ -1530,7 +1444,7 @@ * the default interface setting ... also, setting * the non-default interface clears filters etc. */ - if (ctrl->wValue == 1) { + if (wValue == 1) { usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); netif_carrier_on (dev->net); @@ -1561,36 +1475,36 @@ case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) || !dev->config - || ctrl->wIndex > 1) + || wIndex > 1) break; - if (!(dev->cdc || dev->rndis) && ctrl->wIndex != 0) + if (!(dev->cdc || dev->rndis) && wIndex != 0) break; /* for CDC, iff carrier is on, data interface is active. */ - if (dev->rndis || ctrl->wIndex != 1) + if (dev->rndis || wIndex != 1) *(u8 *)req->buf = 0; else *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; - value = min (ctrl->wLength, (u16) 1); + value = min (wLength, (u16) 1); break; #ifdef DEV_CONFIG_CDC - case CDC_SET_ETHERNET_PACKET_FILTER: + case USB_CDC_SET_ETHERNET_PACKET_FILTER: /* see 6.2.30: no data, wIndex = interface, * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) || !dev->cdc || dev->rndis - || ctrl->wLength != 0 - || ctrl->wIndex > 1) + || wLength != 0 + || wIndex > 1) break; - DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue); + DEBUG (dev, "NOP packet filter %04x\n", wValue); /* NOTE: table 62 has 5 filter bits to reduce traffic, * and we "must" support multicast and promiscuous. * this NOP implements a bad filter (always promisc) */ - dev->cdc_filter = ctrl->wValue; + dev->cdc_filter = wValue; value = 0; break; #endif /* DEV_CONFIG_CDC */ @@ -1599,28 +1513,28 @@ /* RNDIS uses the CDC command encapsulation mechanism to implement * an RPC scheme, with much getting/setting of attributes by OID. */ - case CDC_SEND_ENCAPSULATED_COMMAND: + case USB_CDC_SEND_ENCAPSULATED_COMMAND: if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) || !dev->rndis - || ctrl->wLength > USB_BUFSIZ - || ctrl->wValue + || wLength > USB_BUFSIZ + || wValue || rndis_control_intf.bInterfaceNumber - != ctrl->wIndex) + != wIndex) break; /* read the request, then process it */ - value = ctrl->wLength; + value = wLength; req->complete = rndis_command_complete; /* later, rndis_control_ack () sends a notification */ break; - case CDC_GET_ENCAPSULATED_RESPONSE: + case USB_CDC_GET_ENCAPSULATED_RESPONSE: if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) == ctrl->bRequestType && dev->rndis - // && ctrl->wLength >= 0x0400 - && !ctrl->wValue + // && wLength >= 0x0400 + && !wValue && rndis_control_intf.bInterfaceNumber - == ctrl->wIndex) { + == wIndex) { u8 *buf; /* return the result */ @@ -1640,13 +1554,13 @@ VDEBUG (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, - ctrl->wValue, ctrl->wIndex, ctrl->wLength); + wValue, wIndex, wLength); } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; - req->zero = value < ctrl->wLength + req->zero = value < wLength && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { @@ -1990,7 +1904,7 @@ unsigned long flags; /* FIXME check dev->cdc_filter to decide whether to send this, - * instead of acting as if CDC_PACKET_TYPE_PROMISCUOUS were + * instead of acting as if USB_CDC_PACKET_TYPE_PROMISCUOUS were * always set. RNDIS has the same kind of outgoing filter. */ @@ -2124,13 +2038,13 @@ } /* Send RNDIS RESPONSE_AVAILABLE notification; - * CDC_NOTIFY_RESPONSE_AVAILABLE should work too + * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too */ resp->length = 8; resp->complete = rndis_control_ack_complete; - *((u32 *) resp->buf) = __constant_cpu_to_le32 (1); - *((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); + *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); + *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC); if (length < 0) { @@ -2414,9 +2328,12 @@ "can't run RNDIS on %s\n", gadget->name); return -ENODEV; +#ifdef DEV_CONFIG_CDC + /* pxa25x only does CDC subset; often used with RNDIS */ } else if (cdc) { control_intf.bNumEndpoints = 0; /* FIXME remove endpoint from descriptor list */ +#endif } } #endif diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/net2280.c 2005-02-04 22:22:37 -08:00 @@ -1,8 +1,9 @@ /* - * Driver for the NetChip 2280 USB device controller. - * Specs and errata are available from . + * Driver for the PLX NET2280 USB device controller. + * Specs and errata are available from . * - * NetChip Technology Inc. supported the development of this driver. + * PLX Technology Inc. (formerly NetChip Technology) supported the + * development of this driver. * * * CODE STATUS HIGHLIGHTS @@ -23,7 +24,7 @@ /* * Copyright (C) 2003 David Brownell - * Copyright (C) 2003 NetChip Technologies + * Copyright (C) 2003-2005 PLX Technology, Inc. * * 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 @@ -69,8 +70,8 @@ #include -#define DRIVER_DESC "NetChip 2280 USB Peripheral Controller" -#define DRIVER_VERSION "2004 Jan 14" +#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller" +#define DRIVER_VERSION "2005 Feb 03" #define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ @@ -113,6 +114,16 @@ /* "modprobe net2280 fifo_mode=1" etc */ module_param (fifo_mode, ushort, 0644); +/* enable_suspend -- When enabled, the driver will respond to + * USB suspend requests by powering down the NET2280. Otherwise, + * USB suspend requests will be ignored. This is acceptible for + * self-powered devices, and helps avoid some quirks. + */ +static int enable_suspend = 0; + +/* "modprobe net2280 enable_suspend=1" etc */ +module_param (enable_suspend, bool, S_IRUGO); + #define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") @@ -2561,6 +2572,8 @@ if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend (&dev->gadget); + if (!enable_suspend) + stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) dev->driver->resume (&dev->gadget); diff -Nru a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c --- a/drivers/usb/gadget/omap_udc.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/omap_udc.c 2005-02-04 22:22:37 -08:00 @@ -2,7 +2,7 @@ * omap_udc.c -- for OMAP full speed udc; most chips support OTG. * * Copyright (C) 2004 Texas Instruments, Inc. - * Copyright (C) 2004 David Brownell + * Copyright (C) 2004-2005 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 @@ -2046,7 +2046,10 @@ pullup_disable (udc); } - if (machine_is_omap_innovator()) + /* boards that don't have VBUS sensing can't autogate 48MHz; + * can't enter deep sleep while a gadget driver is active. + */ + if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 1); done: @@ -2064,7 +2067,7 @@ if (!driver || driver != udc->driver) return -EINVAL; - if (machine_is_omap_innovator()) + if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) @@ -2157,13 +2160,13 @@ } } -static char *trx_mode(unsigned m) +static char *trx_mode(unsigned m, int enabled) { switch (m) { - case 3: - case 0: return "6wire"; + case 0: return enabled ? "*6wire" : "unused"; case 1: return "4wire"; case 2: return "3wire"; + case 3: return "6wire"; default: return "unknown"; } } @@ -2171,17 +2174,20 @@ static int proc_otg_show(struct seq_file *s) { u32 tmp; + u32 trans; tmp = OTG_REV_REG; - seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n", - tmp >> 4, tmp & 0xf, - USB_TRANSCEIVER_CTRL_REG); + trans = USB_TRANSCEIVER_CTRL_REG; + seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n", + tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, - trx_mode(USB2_TRX_MODE(tmp)), - trx_mode(USB1_TRX_MODE(tmp)), - trx_mode(USB0_TRX_MODE(tmp)), + trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), + trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), + (USB0_TRX_MODE(tmp) == 0) + ? "internal" + : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", (tmp & HST_IDLE_EN) ? " !host" : "", (tmp & DEV_IDLE_EN) ? " !dev" : "", diff -Nru a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c --- a/drivers/usb/gadget/rndis.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/rndis.c 2005-02-04 22:22:37 -08:00 @@ -730,7 +730,7 @@ /* FIXME use these NDIS_PACKET_TYPE_* bitflags to * filter packets in hard_start_xmit() - * NDIS_PACKET_TYPE_x == CDC_PACKET_TYPE_x for x in: + * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c --- a/drivers/usb/gadget/serial.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/gadget/serial.c 2005-02-04 22:22:37 -08:00 @@ -45,6 +45,7 @@ #include #include +#include #include #include "gadget_chips.h" @@ -122,80 +123,6 @@ }) -/* CDC-ACM Defines and Structures */ - -#define USB_CDC_SUBCLASS_ACM 2 - -#define USB_CDC_CTRL_PROTO_NONE 0 -#define USB_CDC_CTRL_PROTO_AT 1 -#define USB_CDC_CTRL_PROTO_VENDOR 0xff - -#define USB_CDC_SUBTYPE_HEADER 0 -#define USB_CDC_SUBTYPE_CALL_MGMT 1 -#define USB_CDC_SUBTYPE_ACM 2 -#define USB_CDC_SUBTYPE_UNION 6 - -#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01 -#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02 - -#define USB_CDC_REQ_SET_LINE_CODING 0x20 -#define USB_CDC_REQ_GET_LINE_CODING 0x21 -#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 - -#define USB_CDC_1_STOP_BITS 0 -#define USB_CDC_1_5_STOP_BITS 1 -#define USB_CDC_2_STOP_BITS 2 - -#define USB_CDC_NO_PARITY 0 -#define USB_CDC_ODD_PARITY 1 -#define USB_CDC_EVEN_PARITY 2 -#define USB_CDC_MARK_PARITY 3 -#define USB_CDC_SPACE_PARITY 4 - -/* Header Functional Descriptor from CDC spec 5.2.3.1 */ -struct usb_cdc_header_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u16 bcdCDC; -} __attribute__ ((packed)); - -/* Call Management Descriptor from CDC spec 5.2.3.3 */ -struct usb_cdc_call_mgmt_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bmCapabilities; - u8 bDataInterface; -} __attribute__ ((packed)); - -/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */ -struct usb_cdc_acm_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bmCapabilities; -} __attribute__ ((packed)); - -/* Union Functional Descriptor from CDC spec 5.2.3.8 */ -struct usb_cdc_union_desc { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubType; - u8 bMasterInterface0; - u8 bSlaveInterface0; - /* ... and there could be other slave interfaces */ -} __attribute__ ((packed)); - -/* Line Coding Structure from CDC spec 6.2.13 */ -struct usb_cdc_line_coding { - u32 dwDTERate; - u8 bCharFormat; - u8 bParityType; - u8 bDataBits; -} __attribute__ ((packed)); - - /* Defines */ #define GS_VERSION_STR "v2.0" @@ -542,7 +469,7 @@ .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_CTRL_PROTO_AT, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, .iInterface = GS_CONTROL_STR_ID, }; @@ -560,29 +487,29 @@ static const struct usb_cdc_header_desc gs_header_desc = { .bLength = sizeof(gs_header_desc), .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_SUBTYPE_HEADER, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = __constant_cpu_to_le16(0x0110), }; -static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = { +static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { .bLength = sizeof(gs_call_mgmt_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_SUBTYPE_CALL_MGMT, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, .bmCapabilities = 0, .bDataInterface = 1, /* index of data interface */ }; -static struct usb_cdc_acm_desc gs_acm_descriptor = { +static struct usb_cdc_acm_descriptor gs_acm_descriptor = { .bLength = sizeof(gs_acm_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_SUBTYPE_ACM, + .bDescriptorSubType = USB_CDC_ACM_TYPE, .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { .bLength = sizeof(gs_union_desc), .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_SUBTYPE_UNION, + .bDescriptorSubType = USB_CDC_UNION_TYPE, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; @@ -1674,6 +1601,9 @@ int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; + u16 wIndex = ctrl->wIndex; + u16 wValue = ctrl->wValue; + u16 wLength = ctrl->wLength; switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: @@ -1686,15 +1616,15 @@ default: printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } /* respond with data transfer before status phase? */ if (ret >= 0) { req->length = ret; - req->zero = ret < ctrl->wLength + req->zero = ret < wLength && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { @@ -1715,15 +1645,18 @@ int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; + u16 wIndex = ctrl->wIndex; + u16 wValue = ctrl->wValue; + u16 wLength = ctrl->wLength; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; - switch (ctrl->wValue >> 8) { + switch (wValue >> 8) { case USB_DT_DEVICE: - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_device_descriptor)); memcpy(req->buf, &gs_device_desc, ret); break; @@ -1732,7 +1665,7 @@ case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; @@ -1744,18 +1677,18 @@ #endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_buf(req->buf, gadget->speed, - ctrl->wValue >> 8, ctrl->wValue & 0xff, + wValue >> 8, wValue & 0xff, gadget->is_otg); if (ret >= 0) - ret = min(ctrl->wLength, (u16)ret); + ret = min(wLength, (u16)ret); break; case USB_DT_STRING: /* wIndex == language code. */ ret = usb_gadget_get_string(&gs_string_table, - ctrl->wValue & 0xff, req->buf); + wValue & 0xff, req->buf); if (ret >= 0) - ret = min(ctrl->wLength, (u16)ret); + ret = min(wLength, (u16)ret); break; } break; @@ -1764,7 +1697,7 @@ if (ctrl->bRequestType != 0) break; spin_lock(&dev->dev_lock); - ret = gs_set_config(dev, ctrl->wValue); + ret = gs_set_config(dev, wValue); spin_unlock(&dev->dev_lock); break; @@ -1772,18 +1705,19 @@ if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *)req->buf = dev->dev_config; - ret = min(ctrl->wLength, (u16)1); + ret = min(wLength, (u16)1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE - || !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES) + || !dev->dev_config + || wIndex >= GS_MAX_NUM_INTERFACES) break; if (dev->dev_config == GS_BULK_CONFIG_ID - && ctrl->wIndex != GS_BULK_INTERFACE_ID) + && wIndex != GS_BULK_INTERFACE_ID) break; /* no alternate interface settings */ - if (ctrl->wValue != 0) + if (wValue != 0) break; spin_lock(&dev->dev_lock); /* PXA hardware partially handles SET_INTERFACE; @@ -1794,7 +1728,7 @@ goto set_interface_done; } if (dev->dev_config != GS_BULK_CONFIG_ID - && ctrl->wIndex == GS_CONTROL_INTERFACE_ID) { + && wIndex == GS_CONTROL_INTERFACE_ID) { if (dev->dev_notify_ep) { usb_ep_disable(dev->dev_notify_ep); usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc); @@ -1814,21 +1748,21 @@ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) || dev->dev_config == GS_NO_CONFIG_ID) break; - if (ctrl->wIndex >= GS_MAX_NUM_INTERFACES - || (dev->dev_config == GS_BULK_CONFIG_ID - && ctrl->wIndex != GS_BULK_INTERFACE_ID)) { + if (wIndex >= GS_MAX_NUM_INTERFACES + || (dev->dev_config == GS_BULK_CONFIG_ID + && wIndex != GS_BULK_INTERFACE_ID)) { ret = -EDOM; break; } /* no alternate interface settings */ *(u8 *)req->buf = 0; - ret = min(ctrl->wLength, (u16)1); + ret = min(wLength, (u16)1); break; default: printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } @@ -1842,10 +1776,13 @@ struct gs_dev *dev = get_gadget_data(gadget); struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ struct usb_request *req = dev->dev_ctrl_req; + u16 wIndex = ctrl->wIndex; + u16 wValue = ctrl->wValue; + u16 wLength = ctrl->wLength; switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); @@ -1856,7 +1793,7 @@ case USB_CDC_REQ_GET_LINE_CODING: port = dev->dev_port[0]; /* ACM only has one port */ - ret = min(ctrl->wLength, + ret = min(wLength, (u16)sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); @@ -1871,8 +1808,8 @@ default: printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, - ctrl->wIndex, ctrl->wLength); + ctrl->bRequestType, ctrl->bRequest, + wValue, wIndex, wLength); break; } @@ -2272,7 +2209,7 @@ memset(port, 0, sizeof(struct gs_port)); port->port_dev = dev; port->port_num = i; - port->port_line_coding.dwDTERate = GS_DEFAULT_DTE_RATE; + port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE); port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT; port->port_line_coding.bParityType = GS_DEFAULT_PARITY; port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS; @@ -2324,6 +2261,7 @@ } spin_unlock_irqrestore(&port->port_lock, flags); } else { + spin_unlock_irqrestore(&port->port_lock, flags); kfree(port); } diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig --- a/drivers/usb/host/Kconfig 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/Kconfig 2005-02-04 22:22:37 -08:00 @@ -7,13 +7,18 @@ default y if ARM # SL-811 default PCI -# many non-PCI hcds implement OHCI +# many non-PCI SOC chips embed OHCI config USB_ARCH_HAS_OHCI boolean + # ARM: default y if SA1111 default y if ARCH_OMAP default y if ARCH_LH7A404 default y if PXA27x + # PPC: + default y if STB03xxx + default y if PPC_MPC52xx + # more: default PCI # @@ -83,6 +88,35 @@ To compile this driver as a module, choose M here: the module will be called ohci-hcd. + +config USB_OHCI_HCD_PPC_SOC + bool "OHCI support for on-chip PPC USB controller" + depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) + default y + select USB_OHCI_BIG_ENDIAN + ---help--- + Enables support for the USB controller on the MPC52xx or + STB03xxx processor chip. If unsure, say Y. + +config USB_OHCI_HCD_PCI + bool "OHCI support for PCI-bus USB controllers" + depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) + default y + select USB_OHCI_LITTLE_ENDIAN + ---help--- + Enables support for PCI-bus plug-in USB controller cards. + If unsure, say Y. + +config USB_OHCI_BIG_ENDIAN + bool + depends on USB_OHCI_HCD + default n + +config USB_OHCI_LITTLE_ENDIAN + bool + depends on USB_OHCI_HCD + default n if STB03xxx || PPC_MPC52xx + default y config USB_UHCI_HCD tristate "UHCI HCD (most Intel and VIA) support" diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/ohci-dbg.c 2005-02-04 22:22:37 -08:00 @@ -138,7 +138,7 @@ ohci_dbg_sw (controller, next, size, "OHCI %d.%d, %s legacy support registers\n", 0x03 & (temp >> 4), (temp & 0x0f), - (temp & 0x10) ? "with" : "NO"); + (temp & 0x0100) ? "with" : "NO"); temp = ohci_readl (controller, ®s->control); ohci_dbg_sw (controller, next, size, @@ -328,7 +328,7 @@ hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff, hc32_to_cpup (ohci, &td->hwBE)); for (i = 0; i < MAXPSW; i++) { - u16 psw = hc16_to_cpup (ohci, &td->hwPSW [i]); + u16 psw = ohci_hwPSW (ohci, td, i); int cc = (psw >> 12) & 0x0f; ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d\n", i, psw, cc, diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/ohci-hcd.c 2005-02-04 22:22:37 -08:00 @@ -148,10 +148,11 @@ #include "ohci-q.c" -/* Some boards don't support per-port power switching */ -static int power_switching = 0; -module_param (power_switching, bool, 0); -MODULE_PARM_DESC (power_switching, "true (not default) to switch port power"); +/* Some boards misreport power switching/overcurrent */ +static int distrust_firmware = 1; +module_param (distrust_firmware, bool, 0); +MODULE_PARM_DESC (distrust_firmware, + "true to distrust firmware power/overcurrent setup"); /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */ static int no_handshake = 0; @@ -532,8 +533,9 @@ // flush the writes (void) ohci_readl (ohci, &ohci->regs->control); msleep(temp); - if (power_switching) { - unsigned ports = roothub_a (ohci) & RH_A_NDP; + temp = roothub_a (ohci); + if (!(temp & RH_A_NPS)) { + unsigned ports = temp & RH_A_NDP; /* power down each port */ for (temp = 0; temp < ports; temp++) @@ -624,21 +626,16 @@ /* NSC 87560 and maybe others */ temp |= RH_A_NOCP; temp &= ~(RH_A_POTPGT | RH_A_NPS); - } else if (power_switching) { - /* act like most external hubs: use per-port power - * switching and overcurrent reporting. - */ - temp &= ~(RH_A_NPS | RH_A_NOCP); - temp |= RH_A_PSM | RH_A_OCPM; - } else { + ohci_writel (ohci, temp, &ohci->regs->roothub.a); + } else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { /* hub power always on; required for AMD-756 and some * Mac platforms. ganged overcurrent reporting, if any. */ temp |= RH_A_NPS; + ohci_writel (ohci, temp, &ohci->regs->roothub.a); } - ohci_writel (ohci, temp, &ohci->regs->roothub.a); ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); - ohci_writel (ohci, power_switching ? RH_B_PPCM : 0, + ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); @@ -646,7 +643,7 @@ spin_unlock_irq (&ohci->lock); // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((roothub_a (ohci) >> 23) & 0x1fe); + mdelay ((temp >> 23) & 0x1fe); bus = &ohci_to_hcd(ohci)->self; ohci_to_hcd(ohci)->state = USB_STATE_RUNNING; @@ -901,12 +898,17 @@ #include "ohci-au1xxx.c" #endif +#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC +#include "ohci-ppc-soc.c" +#endif + #if !(defined(CONFIG_PCI) \ || defined(CONFIG_SA1111) \ || defined(CONFIG_ARCH_OMAP) \ || defined (CONFIG_ARCH_LH7A404) \ || defined (CONFIG_PXA27x) \ || defined (CONFIG_SOC_AU1X00) \ + || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ ) #error "missing bus glue for ohci-hcd" #endif diff -Nru a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c --- a/drivers/usb/host/ohci-omap.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/ohci-omap.c 2005-02-04 22:22:37 -08:00 @@ -33,11 +33,27 @@ #error "This file is OMAP bus glue. CONFIG_OMAP must be defined." #endif +#ifdef CONFIG_TPS65010 +#include +#else + +#define LOW 0 +#define HIGH 1 + +#define GPIO1 1 + +static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + return 0; +} + +#endif + extern int usb_disabled(void); extern int ocpi_enable(void); /* - * OHCI clock initialization for OMAP-1510 and 1610 + * OHCI clock initialization for OMAP-1510 and 16xx */ static int omap_ohci_clock_power(int on) { @@ -78,7 +94,8 @@ } /* - * Hardware specific transceiver power on/off + * Board specific gang-switched transceiver power on/off. + * NOTE: OSK supplies power from DC, not battery. */ static int omap_ohci_transceiver_power(int on) { @@ -87,17 +104,15 @@ fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, LOW); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, HIGH); } return 0; @@ -177,6 +192,7 @@ { struct omap_usb_config *config = pdev->dev.platform_data; int need_transceiver = (config->otg != 0); + int ret; dev_dbg(&pdev->dev, "starting USB Controller\n"); @@ -213,21 +229,44 @@ } #endif - if (machine_is_omap_osk()) { - omap_request_gpio(9); - omap_set_gpio_direction(9, 1); - omap_set_gpio_dataout(9, 1); - } - omap_ohci_clock_power(1); - omap_ohci_transceiver_power(1); - if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } + if ((ret = ohci_init(ohci)) < 0) + return ret; + + /* board-specific power switching and overcurrent support */ + if (machine_is_omap_osk() || machine_is_omap_innovator()) { + u32 rh = roothub_a (ohci); + + /* power switching (ganged by default) */ + rh &= ~RH_A_NPS; + + /* TPS2045 switch for internal transceiver (port 1) */ + if (machine_is_omap_osk()) { + ohci->power_budget = 250; + + rh &= ~RH_A_NOCP; + + /* gpio9 for overcurrent detction */ + omap_cfg_reg(W8_1610_GPIO9); + omap_request_gpio(9); + omap_set_gpio_direction(9, 1 /* IN */); + + /* for paranoia's sake: disable USB.PUEN */ + omap_cfg_reg(W4_USB_HIGHZ); + } + ohci_writel(ohci, rh, &ohci->regs->roothub.a); + // distrust_firmware = 0; + } + + /* FIXME khubd hub requests should manage power switching */ + omap_ohci_transceiver_power(1); + /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized * too, so all configured ports use the right signaling now. @@ -288,7 +327,8 @@ } if (!request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) { + pdev->resource[0].end - pdev->resource[0].start + 1, + hcd_name)) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); return -EBUSY; } @@ -307,31 +347,31 @@ hcd->regs = (void *)pdev->resource[0].start; hcd->self.controller = &pdev->dev; - retval = omap_start_hc(ohci, pdev); - if (retval < 0) - goto err2; - retval = hcd_buffer_create (hcd); if (retval != 0) { dev_dbg(&pdev->dev, "pool alloc fail\n"); goto err2; } + retval = omap_start_hc(ohci, pdev); + if (retval < 0) + goto err2; + retval = request_irq (hcd->irq, usb_hcd_irq, - SA_INTERRUPT, hcd->driver->description, hcd); + SA_INTERRUPT, hcd_name, hcd); if (retval != 0) { dev_dbg(&pdev->dev, "request_irq failed\n"); retval = -EBUSY; goto err3; } - dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); + dev_info(&pdev->dev, "%s at 0x%p, irq %d\n", + hcd->product_desc, hcd->regs, hcd->irq); hcd->self.bus_name = pdev->dev.bus_id; usb_register_bus (&hcd->self); - if ((retval = driver->start (hcd)) < 0) - { + if ((retval = driver->start (hcd)) < 0) { usb_hcd_omap_remove(hcd, pdev); return retval; } @@ -404,9 +444,6 @@ struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - if ((ret = ohci_init(ohci)) < 0) - return ret; - config = hcd->self.controller->platform_data; if (config->otg || config->rwc) writel(OHCI_CTRL_RWC, &ohci->regs->control); @@ -499,6 +536,8 @@ struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; + if (level != SUSPEND_POWER_DOWN) + return 0; if (state <= dev->power.power_state) return 0; @@ -524,6 +563,9 @@ { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = 0; + + if (level != RESUME_POWER_ON) + return 0; switch (dev->power.power_state) { case 0: diff -Nru a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/host/ohci-ppc-soc.c 2005-02-04 22:22:37 -08:00 @@ -0,0 +1,299 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2003-2005 MontaVista Software Inc. + * + * Bus Glue for PPC On-Chip OHCI driver + * Tested on Freescale MPC5200 and IBM STB04xxx + * + * Modified by Dale Farnsworth from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + +static void usb_hcd_ppc_soc_remove(struct usb_hcd *, struct platform_device *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, + struct usb_hcd **hcd_out, + struct platform_device *pdev) +{ + int retval; + struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; + struct resource *res; + int irq; + struct usb_hcd_platform_data *pd = pdev->dev.platform_data; + + pr_debug("initializing PPC-SOC USB Controller\n"); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + pr_debug(__FILE__ ": no irq\n"); + return -ENODEV; + } + irq = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_debug(__FILE__ ": no reg addr\n"); + return -ENODEV; + } + if (!request_mem_region(res->start, res->end - res->start + 1, + hcd_name)) { + pr_debug(__FILE__ ": request_mem_region failed\n"); + return -EBUSY; + } + + if (pd->start && (retval = pd->start(pdev))) + goto err0; + + hcd = usb_create_hcd(driver); + if (!hcd){ + pr_debug(__FILE__ ": hcd_alloc failed\n"); + retval = -ENOMEM; + goto err1; + } + + ohci = hcd_to_ohci(hcd); + + ohci->flags |= OHCI_BIG_ENDIAN; + + ohci_hcd_init(ohci); + + hcd->irq = irq; + hcd->regs = (struct ohci_regs *) ioremap(res->start, + res->end - res->start + 1); + if (!hcd->regs) { + pr_debug(__FILE__ ": ioremap failed\n"); + retval = -ENOMEM; + goto err2; + } + + hcd->self.controller = &pdev->dev; + + retval = hcd_buffer_create(hcd); + if (retval) { + pr_debug(__FILE__ ": pool alloc fail\n"); + goto err3; + } + + retval = request_irq(hcd->irq, usb_hcd_irq, SA_INTERRUPT, + hcd_name, hcd); + if (retval) { + pr_debug(__FILE__ ": request_irq failed, returned %d\n", + retval); + retval = -EBUSY; + goto err4; + } + + info("%s (PPC-SOC) at 0x%p, irq %d\n", + hcd_name, hcd->regs, hcd->irq); + + hcd->self.bus_name = "PPC-SOC USB"; + + usb_register_bus(&hcd->self); + + if ((retval = driver->start(hcd)) < 0) { + usb_hcd_ppc_soc_remove(hcd, pdev); + return retval; + } + + *hcd_out = hcd; + return 0; + + err4: + hcd_buffer_destroy(hcd); + err3: + iounmap(hcd->regs); + err2: + dev_set_drvdata(&pdev->dev, NULL); + usb_put_hcd(hcd); + err1: + pr_debug("Removing PPC-SOC USB Controller\n"); + if (pd && pd->stop) + pd->stop(pdev); + err0: + release_mem_region(res->start, res->end - res->start + 1); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs + * @pdev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd, struct platform_device *pdev) +{ + struct resource *res; + struct usb_hcd_platform_data *pd = pdev->dev.platform_data; + + pr_debug(__FILE__ ": remove: %s, state %x\n", hcd->self.bus_name, + hcd->state); + if (in_interrupt()) + BUG(); + + hcd->state = USB_STATE_QUIESCING; + + pr_debug("%s: roothub graceful disconnect\n", hcd->self.bus_name); + usb_disconnect(&hcd->self.root_hub); + + hcd->driver->stop(hcd); + hcd->state = USB_STATE_HALT; + + free_irq(hcd->irq, hcd); + hcd_buffer_destroy(hcd); + + usb_deregister_bus(&hcd->self); + + iounmap(hcd->regs); + kfree(hcd); + + pr_debug("stopping PPC-SOC USB Controller\n"); + + if (pd && pd->stop) + pd->stop(pdev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); +} + +static int __devinit +ohci_ppc_soc_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_ppc_soc_hc_driver = { + .description = hcd_name, + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_ppc_soc_start, + .stop = ohci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_USB_SUSPEND + .hub_suspend = ohci_hub_suspend, + .hub_resume = ohci_hub_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +static int ohci_hcd_ppc_soc_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = NULL; + int ret; + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, &hcd, pdev); + + if (ret == 0) + dev_set_drvdata(dev, hcd); + + return ret; +} + +static int ohci_hcd_ppc_soc_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + usb_hcd_ppc_soc_remove(hcd, pdev); + + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct device_driver ohci_hcd_ppc_soc_driver = { + .name = "ppc-soc-ohci", + .bus = &platform_bus_type, + .probe = ohci_hcd_ppc_soc_drv_probe, + .remove = ohci_hcd_ppc_soc_drv_remove, +#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ +#endif +}; + +static int __init ohci_hcd_ppc_soc_init(void) +{ + pr_debug(DRIVER_INFO " (PPC SOC)\n"); + pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), + sizeof(struct td)); + + return driver_register(&ohci_hcd_ppc_soc_driver); +} + +static void __exit ohci_hcd_ppc_soc_cleanup(void) +{ + driver_unregister(&ohci_hcd_ppc_soc_driver); +} + +module_init(ohci_hcd_ppc_soc_init); +module_exit(ohci_hcd_ppc_soc_cleanup); diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/ohci-q.c 2005-02-04 22:22:37 -08:00 @@ -547,7 +547,8 @@ td->hwINFO = cpu_to_hc32 (ohci, info); if (is_iso) { td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); - td->hwPSW [0] = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000); + *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, + (data & 0x0FFF) | 0xE000); td->ed->last_iso = info & 0xffff; } else { td->hwCBP = cpu_to_hc32 (ohci, data); @@ -719,10 +720,12 @@ /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = hc16_to_cpu (ohci, td->hwPSW [0]); + u16 tdPSW = ohci_hwPSW (ohci, td, 0); int dlen = 0; - /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */ + /* NOTE: assumes FC in tdINFO == 0, and that + * only the first of 0..MAXPSW psws is used. + */ cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/ohci.h 2005-02-04 22:22:37 -08:00 @@ -111,8 +111,10 @@ __hc32 hwNextTD; /* Next TD Pointer */ __hc32 hwBE; /* Memory Buffer End Pointer */ - /* PSW is only for ISO */ -#define MAXPSW 1 /* hardware allows 8 */ + /* PSW is only for ISO. Only 1 PSW entry is used, but on + * big-endian PPC hardware that's the second entry. + */ +#define MAXPSW 2 __hc16 hwPSW [MAXPSW]; /* rest are purely for the driver's use */ @@ -183,7 +185,7 @@ /* * OHCI defines u16 frame_no, followed by u16 zero pad. * Since some processors can't do 16 bit bus accesses, - * portable access must be a 32 bit byteswapped access. + * portable access must be a 32 bits wide. */ __hc32 frame_no; /* current frame number */ __hc32 done_head; /* info returned for an interrupt */ @@ -191,8 +193,6 @@ u8 what [4]; /* spec only identifies 252 bytes :) */ } __attribute__ ((aligned(256))); -#define ohci_frame_no(ohci) ((u16)hc32_to_cpup(ohci,&(ohci)->hcca->frame_no)) - /* * This is the structure of the OHCI controller's memory mapped I/O region. * You must use readl() and writel() (in ) to access these fields!! @@ -550,6 +550,44 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) { return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); +} + +/*-------------------------------------------------------------------------*/ + +/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all + * hardware handles 16 bit reads. That creates a different confusion on + * some big-endian SOC implementations. Same thing happens with PSW access. + */ + +#ifdef CONFIG_STB03xxx +#define OHCI_BE_FRAME_NO_SHIFT 16 +#else +#define OHCI_BE_FRAME_NO_SHIFT 0 +#endif + +static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) +{ + u32 tmp; + if (big_endian(ohci)) { + tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); + tmp >>= OHCI_BE_FRAME_NO_SHIFT; + } else + tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); + + return (u16)tmp; +} + +static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, + const struct td *td, int index) +{ + return (__hc16 *)(big_endian(ohci) ? + &td->hwPSW[index ^ 1] : &td->hwPSW[index]); +} + +static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci, + const struct td *td, int index) +{ + return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index)); } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/uhci-debug.c 2005-02-04 22:22:37 -08:00 @@ -17,6 +17,8 @@ #include "uhci-hcd.h" +static struct dentry *uhci_debugfs_root = NULL; + /* Handle REALLY large printk's so we don't overflow buffers */ static inline void lprintk(char *buf) { @@ -497,8 +499,6 @@ #define MAX_OUTPUT (64 * 1024) -static struct dentry *uhci_debugfs_root = NULL; - struct uhci_debug { int size; char *data; @@ -579,4 +579,9 @@ .read = uhci_debug_read, .release = uhci_debug_release, }; + +#else /* CONFIG_DEBUG_FS */ + +#define uhci_debug_operations (* (struct file_operations *) NULL) + #endif diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c 2005-02-04 22:22:37 -08:00 +++ b/drivers/usb/host/uhci-hcd.c 2005-02-04 22:22:37 -08:00 @@ -87,19 +87,9 @@ static char *errbuf; #define ERRBUF_LEN (32 * 1024) -#include "uhci-hub.c" -#include "uhci-debug.c" - static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci); -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); -static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); -static void uhci_remove_pending_urbps(struct uhci_hcd *uhci); -static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs); -static void uhci_free_pending_qhs(struct uhci_hcd *uhci); -static void uhci_free_pending_tds(struct uhci_hcd *uhci); - static void hc_state_transitions(struct uhci_hcd *uhci); /* If a transfer is still active after this much time, turn off FSBR */ @@ -111,1424 +101,9 @@ /* to make sure it doesn't hog all of the bandwidth */ #define DEPTH_INTERVAL 5 -/* - * Technically, updating td->status here is a race, but it's not really a - * problem. The worst that can happen is that we set the IOC bit again - * generating a spurious interrupt. We could fix this by creating another - * QH and leaving the IOC bit always set, but then we would have to play - * games with the FSBR code to make sure we get the correct order in all - * the cases. I don't think it's worth the effort - */ -static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) -{ - uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); -} - -static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) -{ - uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); -} - -static inline void uhci_moveto_complete(struct uhci_hcd *uhci, - struct urb_priv *urbp) -{ - list_move_tail(&urbp->urb_list, &uhci->complete_list); -} - -static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) -{ - dma_addr_t dma_handle; - struct uhci_td *td; - - td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle); - if (!td) - return NULL; - - td->dma_handle = dma_handle; - - td->link = UHCI_PTR_TERM; - td->buffer = 0; - - td->frame = -1; - td->dev = dev; - - INIT_LIST_HEAD(&td->list); - INIT_LIST_HEAD(&td->remove_list); - INIT_LIST_HEAD(&td->fl_list); - - usb_get_dev(dev); - - return td; -} - -static inline void uhci_fill_td(struct uhci_td *td, u32 status, - u32 token, u32 buffer) -{ - td->status = cpu_to_le32(status); - td->token = cpu_to_le32(token); - td->buffer = cpu_to_le32(buffer); -} - -/* - * We insert Isochronous URB's directly into the frame list at the beginning - */ -static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) -{ - framenum &= (UHCI_NUMFRAMES - 1); - - td->frame = framenum; - - /* Is there a TD already mapped there? */ - if (uhci->fl->frame_cpu[framenum]) { - struct uhci_td *ftd, *ltd; - - ftd = uhci->fl->frame_cpu[framenum]; - ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); - - list_add_tail(&td->fl_list, &ftd->fl_list); - - td->link = ltd->link; - wmb(); - ltd->link = cpu_to_le32(td->dma_handle); - } else { - td->link = uhci->fl->frame[framenum]; - wmb(); - uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); - uhci->fl->frame_cpu[framenum] = td; - } -} - -static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) -{ - /* If it's not inserted, don't remove it */ - if (td->frame == -1 && list_empty(&td->fl_list)) - return; - - if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { - if (list_empty(&td->fl_list)) { - uhci->fl->frame[td->frame] = td->link; - uhci->fl->frame_cpu[td->frame] = NULL; - } else { - struct uhci_td *ntd; - - ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); - uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); - uhci->fl->frame_cpu[td->frame] = ntd; - } - } else { - struct uhci_td *ptd; - - ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list); - ptd->link = td->link; - } - - wmb(); - td->link = UHCI_PTR_TERM; - - list_del_init(&td->fl_list); - td->frame = -1; -} - -/* - * Inserts a td list into qh. - */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - __le32 *plink; - - /* Ordering isn't important here yet since the QH hasn't been */ - /* inserted into the schedule yet */ - plink = &qh->element; - list_for_each_entry(td, &urbp->td_list, list) { - *plink = cpu_to_le32(td->dma_handle) | breadth; - plink = &td->link; - } - *plink = UHCI_PTR_TERM; -} - -static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) -{ - if (!list_empty(&td->list)) - dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); - if (!list_empty(&td->remove_list)) - dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); - if (!list_empty(&td->fl_list)) - dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); - - if (td->dev) - usb_put_dev(td->dev); - - dma_pool_free(uhci->td_pool, td, td->dma_handle); -} - -static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev) -{ - dma_addr_t dma_handle; - struct uhci_qh *qh; - - qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle); - if (!qh) - return NULL; - - qh->dma_handle = dma_handle; - - qh->element = UHCI_PTR_TERM; - qh->link = UHCI_PTR_TERM; - - qh->dev = dev; - qh->urbp = NULL; - - INIT_LIST_HEAD(&qh->list); - INIT_LIST_HEAD(&qh->remove_list); - - usb_get_dev(dev); - - return qh; -} - -static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - if (!list_empty(&qh->list)) - dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh); - if (!list_empty(&qh->remove_list)) - dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh); - - if (qh->dev) - usb_put_dev(qh->dev); - - dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); -} - -/* - * Append this urb's qh after the last qh in skelqh->list - * - * Note that urb_priv.queue_list doesn't have a separate queue head; - * it's a ring with every element "live". - */ -static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct urb_priv *turbp; - struct uhci_qh *lqh; - - /* Grab the last QH */ - lqh = list_entry(skelqh->list.prev, struct uhci_qh, list); - - /* Point to the next skelqh */ - urbp->qh->link = lqh->link; - wmb(); /* Ordering is important */ - - /* - * Patch QHs for previous endpoint's queued URBs? HC goes - * here next, not to the next skelqh it now points to. - * - * lqh --> td ... --> qh ... --> td --> qh ... --> td - * | | | - * v v v - * +<----------------+-----------------+ - * v - * newqh --> td ... --> td - * | - * v - * ... - * - * The HC could see (and use!) any of these as we write them. - */ - lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - if (lqh->urbp) { - list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list) - turbp->qh->link = lqh->link; - } - - list_add_tail(&urbp->qh->list, &skelqh->list); -} - -/* - * Start removal of QH from schedule; it finishes next frame. - * TDs should be unlinked before this is called. - */ -static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct uhci_qh *pqh; - __le32 newlink; - unsigned int age; - - if (!qh) - return; - - /* - * Only go through the hoops if it's actually linked in - */ - if (!list_empty(&qh->list)) { - - /* If our queue is nonempty, make the next URB the head */ - if (!list_empty(&qh->urbp->queue_list)) { - struct urb_priv *nurbp; - - nurbp = list_entry(qh->urbp->queue_list.next, - struct urb_priv, queue_list); - nurbp->queued = 0; - list_add(&nurbp->qh->list, &qh->list); - newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - } else - newlink = qh->link; - - /* Fix up the previous QH's queue to link to either - * the new head of this queue or the start of the - * next endpoint's queue. */ - pqh = list_entry(qh->list.prev, struct uhci_qh, list); - pqh->link = newlink; - if (pqh->urbp) { - struct urb_priv *turbp; - - list_for_each_entry(turbp, &pqh->urbp->queue_list, - queue_list) - turbp->qh->link = newlink; - } - wmb(); - - /* Leave qh->link in case the HC is on the QH now, it will */ - /* continue the rest of the schedule */ - qh->element = UHCI_PTR_TERM; - - list_del_init(&qh->list); - } - - list_del_init(&qh->urbp->queue_list); - qh->urbp = NULL; - - age = uhci_get_current_frame_number(uhci); - if (age != uhci->qh_remove_age) { - uhci_free_pending_qhs(uhci); - uhci->qh_remove_age = age; - } - - /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the QH */ - if (list_empty(&uhci->qh_remove_list)) - uhci_set_next_interrupt(uhci); - - list_add(&qh->remove_list, &uhci->qh_remove_list); -} - -static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - - list_for_each_entry(td, &urbp->td_list, list) { - if (toggle) - td->token |= cpu_to_le32(TD_TOKEN_TOGGLE); - else - td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE); - - toggle ^= 1; - } - - return toggle; -} - -/* This function will append one URB's QH to another URB's QH. This is for */ -/* queuing interrupt, control or bulk transfers */ -static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb) -{ - struct urb_priv *eurbp, *urbp, *furbp, *lurbp; - struct uhci_td *lltd; - - eurbp = eurb->hcpriv; - urbp = urb->hcpriv; - - /* Find the first URB in the queue */ - furbp = eurbp; - if (eurbp->queued) { - list_for_each_entry(furbp, &eurbp->queue_list, queue_list) - if (!furbp->queued) - break; - } - - lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); - - lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); - - /* Control transfers always start with toggle 0 */ - if (!usb_pipecontrol(urb->pipe)) - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), - uhci_fixup_toggle(urb, - uhci_toggle(td_token(lltd)) ^ 1)); - - /* All qh's in the queue need to link to the next queue */ - urbp->qh->link = eurbp->qh->link; - - wmb(); /* Make sure we flush everything */ - - lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - - list_add_tail(&urbp->queue_list, &furbp->queue_list); - - urbp->queued = 1; -} - -static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp, *nurbp, *purbp, *turbp; - struct uhci_td *pltd; - unsigned int toggle; - - urbp = urb->hcpriv; - - if (list_empty(&urbp->queue_list)) - return; - - nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); - - /* - * Fix up the toggle for the following URBs in the queue. - * Only needed for bulk and interrupt: control and isochronous - * endpoints don't propagate toggles between messages. - */ - if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) { - if (!urbp->queued) - /* We just set the toggle in uhci_unlink_generic */ - toggle = usb_gettoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - else { - /* If we're in the middle of the queue, grab the */ - /* toggle from the TD previous to us */ - purbp = list_entry(urbp->queue_list.prev, - struct urb_priv, queue_list); - pltd = list_entry(purbp->td_list.prev, - struct uhci_td, list); - toggle = uhci_toggle(td_token(pltd)) ^ 1; - } - - list_for_each_entry(turbp, &urbp->queue_list, queue_list) { - if (!turbp->queued) - break; - toggle = uhci_fixup_toggle(turbp->urb, toggle); - } - - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), toggle); - } - - if (urbp->queued) { - /* We're somewhere in the middle (or end). The case where - * we're at the head is handled in uhci_remove_qh(). */ - purbp = list_entry(urbp->queue_list.prev, struct urb_priv, - queue_list); - - pltd = list_entry(purbp->td_list.prev, struct uhci_td, list); - if (nurbp->queued) - pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - else - /* The next URB happens to be the beginning, so */ - /* we're the last, end the chain */ - pltd->link = UHCI_PTR_TERM; - } - - /* urbp->queue_list is handled in uhci_remove_qh() */ -} - -static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp; - - urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC); - if (!urbp) - return NULL; - - memset((void *)urbp, 0, sizeof(*urbp)); - - urbp->inserttime = jiffies; - urbp->fsbrtime = jiffies; - urbp->urb = urb; - - INIT_LIST_HEAD(&urbp->td_list); - INIT_LIST_HEAD(&urbp->queue_list); - INIT_LIST_HEAD(&urbp->urb_list); - - list_add_tail(&urbp->urb_list, &uhci->urb_list); - - urb->hcpriv = urbp; - - return urbp; -} - -static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - - td->urb = urb; - - list_add_tail(&td->list, &urbp->td_list); -} - -static void uhci_remove_td_from_urb(struct uhci_td *td) -{ - if (list_empty(&td->list)) - return; - - list_del_init(&td->list); - - td->urb = NULL; -} - -static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) -{ - struct uhci_td *td, *tmp; - struct urb_priv *urbp; - unsigned int age; - - urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; - - if (!list_empty(&urbp->urb_list)) - dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " - "or uhci->remove_list!\n", urb); - - age = uhci_get_current_frame_number(uhci); - if (age != uhci->td_remove_age) { - uhci_free_pending_tds(uhci); - uhci->td_remove_age = age; - } - - /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the TD's*/ - if (list_empty(&uhci->td_remove_list)) - uhci_set_next_interrupt(uhci); - - list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { - uhci_remove_td_from_urb(td); - uhci_remove_td(uhci, td); - list_add(&td->remove_list, &uhci->td_remove_list); - } - - urb->hcpriv = NULL; - kmem_cache_free(uhci_up_cachep, urbp); -} - -static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - - if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) { - urbp->fsbr = 1; - if (!uhci->fsbr++ && !uhci->fsbrtimeout) - uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; - } -} - -static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - - if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) { - urbp->fsbr = 0; - if (!--uhci->fsbr) - uhci->fsbrtimeout = jiffies + FSBR_DELAY; - } -} - -/* - * Map status to standard result codes - * - * is (td_status(td) & 0xF60000), a.k.a. - * uhci_status_bits(td_status(td)). - * Note: 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) -{ - if (!status) - return 0; - if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ - return -EPROTO; - if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ - if (dir_out) - return -EPROTO; - else - return -EILSEQ; - } - 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; - WARN_ON(status & TD_CTRL_ACTIVE); /* Active */ - return 0; -} - -/* - * Control transfers - */ -static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - struct uhci_qh *qh, *skelqh; - unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - int len = urb->transfer_buffer_length; - dma_addr_t data = urb->transfer_dma; - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; - - /* 3 errors */ - status = TD_CTRL_ACTIVE | uhci_maxerr(3); - if (urb->dev->speed == USB_SPEED_LOW) - status |= TD_CTRL_LS; - - /* - * Build the TD for the control request setup packet - */ - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(7), - urb->setup_dma); - - /* - * If direction is "send", change the packet ID from SETUP (0x2D) - * to OUT (0xE1). Else change it from SETUP to IN (0x69) and - * set Short Packet Detect (SPD) for all data packets. - */ - if (usb_pipeout(urb->pipe)) - destination ^= (USB_PID_SETUP ^ USB_PID_OUT); - else { - destination ^= (USB_PID_SETUP ^ USB_PID_IN); - status |= TD_CTRL_SPD; - } - - /* - * Build the DATA TD's - */ - while (len > 0) { - int pktsze = len; - - if (pktsze > maxsze) - pktsze = maxsze; - - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - /* Alternate Data0/1 (start with Data1) */ - destination ^= TD_TOKEN_TOGGLE; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1), - data); - - data += pktsze; - len -= pktsze; - } - - /* - * Build the final TD for control status - */ - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - /* - * It's IN if the pipe is an output pipe or we're not expecting - * data back. - */ - destination &= ~TD_TOKEN_PID_MASK; - if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) - destination |= USB_PID_IN; - else - destination |= USB_PID_OUT; - - destination |= TD_TOKEN_TOGGLE; /* End in Data1 */ - - status &= ~TD_CTRL_SPD; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status | TD_CTRL_IOC, - destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0); - - qh = uhci_alloc_qh(uhci, urb->dev); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; - - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); - - /* Low-speed transfers get a different queue, and won't hog the bus. - * Also, some devices enumerate better without FSBR; the easiest way - * to do that is to put URBs on the low-speed queue while the device - * is in the DEFAULT state. */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->state == USB_STATE_DEFAULT) - skelqh = uhci->skel_ls_control_qh; - else { - skelqh = uhci->skel_fs_control_qh; - uhci_inc_fsbr(uhci, urb); - } - - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; -} - -/* - * If control-IN transfer was short, the status packet wasn't sent. - * This routine changes the element pointer in the QH to point at the - * status TD. It's safe to do this even while the QH is live, because - * the hardware only updates the element pointer following a successful - * transfer. The inactive TD for the short packet won't cause an update, - * so the pointer won't get overwritten. The next time the controller - * sees this QH, it will send the status packet. - */ -static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - - urbp->short_control_packet = 1; - - td = list_entry(urbp->td_list.prev, struct uhci_td, list); - urbp->qh->element = cpu_to_le32(td->dma_handle); - - return -EINPROGRESS; -} - - -static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) -{ - struct list_head *tmp, *head; - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - unsigned int status; - int ret = 0; - - if (list_empty(&urbp->td_list)) - return -EINVAL; - - head = &urbp->td_list; - - if (urbp->short_control_packet) { - tmp = head->prev; - goto status_stage; - } - - tmp = head->next; - td = list_entry(tmp, struct uhci_td, list); - - /* 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) - return -EINPROGRESS; - - if (status) - goto td_error; - - urb->actual_length = 0; - - /* The rest of the TD's (but the last) are data */ - tmp = tmp->next; - while (tmp != head && tmp->next != head) { - unsigned int ctrlstat; - - td = list_entry(tmp, struct uhci_td, list); - tmp = tmp->next; - - ctrlstat = td_status(td); - status = uhci_status_bits(ctrlstat); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - urb->actual_length += uhci_actual_length(ctrlstat); - - if (status) - goto td_error; - - /* Check to see if we received a short packet */ - if (uhci_actual_length(ctrlstat) < - uhci_expected_length(td_token(td))) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) { - ret = -EREMOTEIO; - goto err; - } - - if (uhci_packetid(td_token(td)) == USB_PID_IN) - return usb_control_retrigger_status(uhci, urb); - else - return 0; - } - } - -status_stage: - td = list_entry(tmp, struct uhci_td, list); - - /* Control status stage */ - status = td_status(td); - -#ifdef I_HAVE_BUGGY_APC_BACKUPS - /* APC BackUPS Pro kludge */ - /* It tries to send all of the descriptor instead of the amount */ - /* we requested */ - if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */ - status & TD_CTRL_ACTIVE && - status & TD_CTRL_NAK) - return 0; -#endif - - status = uhci_status_bits(status); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - if (status) - goto td_error; - - return 0; - -td_error: - ret = uhci_map_status(status, uhci_packetout(td_token(td))); - -err: - if ((debug == 1 && ret != -EPIPE) || debug > 1) { - /* Some debugging code */ - dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", - __FUNCTION__, status); - - if (errbuf) { - /* Print the chain for debugging purposes */ - uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - - lprintk(errbuf); - } - } - - return ret; -} - -/* - * Common submit for bulk and interrupt - */ -static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh) -{ - struct uhci_td *td; - struct uhci_qh *qh; - unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - int len = urb->transfer_buffer_length; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - dma_addr_t data = urb->transfer_dma; - - if (len < 0) - return -EINVAL; - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - - status = uhci_maxerr(3) | TD_CTRL_ACTIVE; - if (urb->dev->speed == USB_SPEED_LOW) - status |= TD_CTRL_LS; - if (usb_pipein(urb->pipe)) - status |= TD_CTRL_SPD; - - /* - * Build the DATA TD's - */ - do { /* Allow zero length packets */ - int pktsze = maxsze; - - if (pktsze >= len) { - pktsze = len; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - status &= ~TD_CTRL_SPD; - } - - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) | - (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), - data); - - data += pktsze; - len -= maxsze; - - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - } while (len > 0); - - /* - * URB_ZERO_PACKET means adding a 0-length packet, if direction - * is OUT and the transfer_length was an exact multiple of maxsze, - * hence (len = transfer_length - N * maxsze) == 0 - * however, if transfer_length == 0, the zero packet was already - * prepared above. - */ - if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) && - !len && urb->transfer_buffer_length) { - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) | - (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), - data); - - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - } - - /* Set the interrupt-on-completion flag on the last packet. - * A more-or-less typical 4 KB URB (= size of one memory page) - * will require about 3 ms to transfer; that's a little on the - * fast side but not enough to justify delaying an interrupt - * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT - * flag setting. */ - td->status |= cpu_to_le32(TD_CTRL_IOC); - - qh = uhci_alloc_qh(uhci, urb->dev); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; - - /* Always breadth first */ - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); - - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; -} - -/* - * Common result for bulk and interrupt - */ -static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - unsigned int status = 0; - int ret = 0; - - urb->actual_length = 0; - - list_for_each_entry(td, &urbp->td_list, list) { - unsigned int ctrlstat = td_status(td); - - status = uhci_status_bits(ctrlstat); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - urb->actual_length += uhci_actual_length(ctrlstat); - - if (status) - goto td_error; - - if (uhci_actual_length(ctrlstat) < - uhci_expected_length(td_token(td))) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) { - ret = -EREMOTEIO; - goto err; - } else - return 0; - } - } - - return 0; - -td_error: - ret = uhci_map_status(status, uhci_packetout(td_token(td))); - -err: - /* - * Enable this chunk of code if you want to see some more debugging. - * But be careful, it has the tendancy to starve out khubd and prevent - * disconnects from happening successfully if you have a slow debug - * log interface (like a serial console. - */ -#if 0 - if ((debug == 1 && ret != -EPIPE) || debug > 1) { - /* Some debugging code */ - dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", - __FUNCTION__, status); - - if (errbuf) { - /* Print the chain for debugging purposes */ - uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - - lprintk(errbuf); - } - } -#endif - return ret; -} - -static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) -{ - int ret; - - /* Can't have low-speed bulk transfers */ - if (urb->dev->speed == USB_SPEED_LOW) - return -EINVAL; - - ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh); - if (ret == -EINPROGRESS) - uhci_inc_fsbr(uhci, urb); - - return ret; -} - -static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) -{ - /* USB 1.1 interrupt transfers only involve one packet per interval; - * that's the uhci_submit_common() "breadth first" policy. Drivers - * can submit urbs of any length, but longer ones might need many - * intervals to complete. - */ - return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]); -} - -/* - * Isochronous transfers - */ -static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) -{ - struct urb *last_urb = NULL; - struct urb_priv *up; - int ret = 0; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - /* look for pending URB's with identical pipe handle */ - if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && - (u->status == -EINPROGRESS) && (u != urb)) { - if (!last_urb) - *start = u->start_frame; - last_urb = u; - } - } - - if (last_urb) { - *end = (last_urb->start_frame + last_urb->number_of_packets * - last_urb->interval) & (UHCI_NUMFRAMES-1); - ret = 0; - } else - ret = -1; /* no previous urb found */ - - return ret; -} - -static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) -{ - int limits; - unsigned int start = 0, end = 0; - - if (urb->number_of_packets > 900) /* 900? Why? */ - return -EFBIG; - - limits = isochronous_find_limits(uhci, urb, &start, &end); - - if (urb->transfer_flags & URB_ISO_ASAP) { - if (limits) - urb->start_frame = - (uhci_get_current_frame_number(uhci) + - 10) & (UHCI_NUMFRAMES - 1); - else - urb->start_frame = end; - } else { - urb->start_frame &= (UHCI_NUMFRAMES - 1); - /* FIXME: Sanity check */ - } - - return 0; -} - -/* - * Isochronous transfers - */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) -{ - struct uhci_td *td; - int i, ret, frame; - int status, destination; - - status = TD_CTRL_ACTIVE | TD_CTRL_IOS; - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - - ret = isochronous_find_start(uhci, urb); - if (ret) - return ret; - - frame = urb->start_frame; - for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) { - if (!urb->iso_frame_desc[i].length) - continue; - - td = uhci_alloc_td(uhci, urb->dev); - if (!td) - return -ENOMEM; - - uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1), - urb->transfer_dma + urb->iso_frame_desc[i].offset); - - if (i + 1 >= urb->number_of_packets) - td->status |= cpu_to_le32(TD_CTRL_IOC); - - uhci_insert_td_frame_list(uhci, td, frame); - } - - return -EINPROGRESS; -} - -static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) -{ - struct uhci_td *td; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - int status; - int i, ret = 0; - - urb->actual_length = 0; - - i = 0; - list_for_each_entry(td, &urbp->td_list, list) { - int actlength; - unsigned int ctrlstat = td_status(td); - - if (ctrlstat & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - actlength = uhci_actual_length(ctrlstat); - urb->iso_frame_desc[i].actual_length = actlength; - urb->actual_length += actlength; - - status = uhci_map_status(uhci_status_bits(ctrlstat), - usb_pipeout(urb->pipe)); - urb->iso_frame_desc[i].status = status; - if (status) { - urb->error_count++; - ret = status; - } - - i++; - } - - return ret; -} - -static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *up; - - /* We don't match Isoc transfers since they are special */ - if (usb_pipeisoc(urb->pipe)) - return NULL; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - if (u->dev == urb->dev && u->status == -EINPROGRESS) { - /* For control, ignore the direction */ - if (usb_pipecontrol(urb->pipe) && - (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN)) - return u; - else if (u->pipe == urb->pipe) - return u; - } - } - - return NULL; -} - -static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, int mem_flags) -{ - int ret; - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; - struct urb *eurb; - int bustime; - - spin_lock_irqsave(&uhci->schedule_lock, flags); - - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto out; - - eurb = uhci_find_urb_ep(uhci, urb); - - if (!uhci_alloc_urb_priv(uhci, urb)) { - ret = -ENOMEM; - goto out; - } - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - ret = uhci_submit_control(uhci, urb, eurb); - break; - case PIPE_INTERRUPT: - if (!eurb) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - ret = bustime; - else { - ret = uhci_submit_interrupt(uhci, urb, eurb); - if (ret == -EINPROGRESS) - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - } - } else { /* inherit from parent */ - urb->bandwidth = eurb->bandwidth; - ret = uhci_submit_interrupt(uhci, urb, eurb); - } - break; - case PIPE_BULK: - ret = uhci_submit_bulk(uhci, urb, eurb); - break; - case PIPE_ISOCHRONOUS: - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - ret = bustime; - break; - } - - ret = uhci_submit_isochronous(uhci, urb); - if (ret == -EINPROGRESS) - usb_claim_bandwidth(urb->dev, urb, bustime, 1); - break; - } - - if (ret != -EINPROGRESS) { - /* Submit failed, so delete it from the urb_list */ - struct urb_priv *urbp = urb->hcpriv; - - list_del_init(&urbp->urb_list); - uhci_destroy_urb_priv(uhci, urb); - } else - ret = 0; - -out: - spin_unlock_irqrestore(&uhci->schedule_lock, flags); - return ret; -} - -/* - * Return the result of a transfer - */ -static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) -{ - int ret = -EINPROGRESS; - struct urb_priv *urbp; - - spin_lock(&urb->lock); - - urbp = (struct urb_priv *)urb->hcpriv; - - if (urb->status != -EINPROGRESS) /* URB already dequeued */ - goto out; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - ret = uhci_result_control(uhci, urb); - break; - case PIPE_BULK: - case PIPE_INTERRUPT: - ret = uhci_result_common(uhci, urb); - break; - case PIPE_ISOCHRONOUS: - ret = uhci_result_isochronous(uhci, urb); - break; - } - - if (ret == -EINPROGRESS) - goto out; - urb->status = ret; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: - case PIPE_ISOCHRONOUS: - /* Release bandwidth for Interrupt or Isoc. transfers */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 1); - uhci_unlink_generic(uhci, urb); - break; - case PIPE_INTERRUPT: - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Make sure we don't release if we have a queued URB */ - if (list_empty(&urbp->queue_list) && urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 0); - else - /* bandwidth was passed on to queued URB, */ - /* so don't let usb_unlink_urb() release it */ - urb->bandwidth = 0; - uhci_unlink_generic(uhci, urb); - break; - default: - dev_info(uhci_dev(uhci), "%s: unknown pipe type %d " - "for urb %p\n", - __FUNCTION__, usb_pipetype(urb->pipe), urb); - } - - /* Move it from uhci->urb_list to uhci->complete_list */ - uhci_moveto_complete(uhci, urbp); - -out: - spin_unlock(&urb->lock); -} - -static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) -{ - struct list_head *head; - struct uhci_td *td; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - int prevactive = 0; - - uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ - - /* - * Now we need to find out what the last successful toggle was - * so we can update the local data toggle for the next transfer - * - * There are 2 ways the last successful completed TD is found: - * - * 1) The TD is NOT active and the actual length < expected length - * 2) The TD is NOT active and it's the last TD in the chain - * - * and a third way the first uncompleted TD is found: - * - * 3) The TD is active and the previous TD is NOT active - * - * Control and Isochronous ignore the toggle, so this is safe - * for all types - * - * FIXME: The toggle fixups won't be 100% reliable until we - * change over to using a single queue for each endpoint and - * stop the queue before unlinking. - */ - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - unsigned int ctrlstat = td_status(td); - - if (!(ctrlstat & TD_CTRL_ACTIVE) && - (uhci_actual_length(ctrlstat) < - uhci_expected_length(td_token(td)) || - td->list.next == head)) - usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td)), - uhci_toggle(td_token(td)) ^ 1); - else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) - usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td)), - uhci_toggle(td_token(td))); - - prevactive = ctrlstat & TD_CTRL_ACTIVE; - } - - uhci_delete_queued_urb(uhci, urb); - - /* The interrupt loop will reclaim the QH's */ - uhci_remove_qh(uhci, urbp->qh); - urbp->qh = NULL; -} - -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; - unsigned int age; - - spin_lock_irqsave(&uhci->schedule_lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ - goto done; - list_del_init(&urbp->urb_list); - - uhci_unlink_generic(uhci, urb); - - age = uhci_get_current_frame_number(uhci); - if (age != uhci->urb_remove_age) { - uhci_remove_pending_urbps(uhci); - uhci->urb_remove_age = age; - } - - /* If we're the first, set the next interrupt bit */ - if (list_empty(&uhci->urb_remove_list)) - uhci_set_next_interrupt(uhci); - list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); - -done: - spin_unlock_irqrestore(&uhci->schedule_lock, flags); - return 0; -} - -static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head; - struct uhci_td *td; - int count = 0; - - uhci_dec_fsbr(uhci, urb); - - urbp->fsbr_timeout = 1; - - /* - * Ideally we would want to fix qh->element as well, but it's - * read/write by the HC, so that can introduce a race. It's not - * really worth the hassle - */ - - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - /* - * Make sure we don't do the last one (since it'll have the - * TERM bit set) as well as we skip every so many TD's to - * make sure it doesn't hog the bandwidth - */ - if (td->list.next != head && (count % DEPTH_INTERVAL) == - (DEPTH_INTERVAL - 1)) - td->link |= UHCI_PTR_DEPTH; - - count++; - } - - return 0; -} - -/* - * uhci_get_current_frame_number() - * - * returns the current frame number for a USB bus/controller. - */ -static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci) -{ - return inw(uhci->io_addr + USBFRNUM); -} +#include "uhci-hub.c" +#include "uhci-debug.c" +#include "uhci-q.c" static int init_stall_timer(struct usb_hcd *hcd); @@ -1592,62 +167,6 @@ return 0; } -static void uhci_free_pending_qhs(struct uhci_hcd *uhci) -{ - struct uhci_qh *qh, *tmp; - - list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) { - list_del_init(&qh->remove_list); - - uhci_free_qh(uhci, qh); - } -} - -static void uhci_free_pending_tds(struct uhci_hcd *uhci) -{ - struct uhci_td *td, *tmp; - - list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) { - list_del_init(&td->remove_list); - - uhci_free_td(uhci, td); - } -} - -static void -uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) -__releases(uhci->schedule_lock) -__acquires(uhci->schedule_lock) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - uhci_destroy_urb_priv(uhci, urb); - - spin_unlock(&uhci->schedule_lock); - usb_hcd_giveback_urb(hcd, urb, regs); - spin_lock(&uhci->schedule_lock); -} - -static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct urb_priv *urbp, *tmp; - - list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) { - struct urb *urb = urbp->urb; - - list_del_init(&urbp->urb_list); - uhci_finish_urb(hcd, urb, regs); - } -} - -static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) -{ - - /* Splice the urb_remove_list onto the end of the complete_list */ - list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); -} - static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -1866,6 +385,14 @@ } } +/* + * returns the cu