diff options
Diffstat (limited to 'drivers/staging/most/hdm-usb/hdm_usb.c')
-rw-r--r-- | drivers/staging/most/hdm-usb/hdm_usb.c | 502 |
1 files changed, 230 insertions, 272 deletions
diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c index aeae071f2823..26c9adb29308 100644 --- a/drivers/staging/most/hdm-usb/hdm_usb.c +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -43,8 +43,9 @@ #define USB_VENDOR_ID_SMSC 0x0424 /* VID: SMSC */ #define USB_DEV_ID_BRDG 0xC001 /* PID: USB Bridge */ -#define USB_DEV_ID_INIC 0xCF18 /* PID: USB INIC */ -#define HW_RESYNC 0x0000 +#define USB_DEV_ID_OS81118 0xCF18 /* PID: USB OS81118 */ +#define USB_DEV_ID_OS81119 0xCF19 /* PID: USB OS81119 */ +#define USB_DEV_ID_OS81210 0xCF30 /* PID: USB OS81210 */ /* DRCI Addresses */ #define DRCI_REG_NI_STATE 0x0100 #define DRCI_REG_PACKET_BW 0x0101 @@ -64,33 +65,30 @@ #define DRCI_WRITE_REQ 0xA1 /** - * struct buf_anchor - used to create a list of pending URBs - * @urb: pointer to USB request block - * @clear_work_obj: - * @list: linked list - * @urb_completion: - */ -struct buf_anchor { - struct urb *urb; - struct work_struct clear_work_obj; - struct list_head list; - struct completion urb_compl; -}; - -#define to_buf_anchor(w) container_of(w, struct buf_anchor, clear_work_obj) - -/** * struct most_dci_obj - Direct Communication Interface * @kobj:position in sysfs * @usb_device: pointer to the usb device + * @reg_addr: register address for arbitrary DCI access */ struct most_dci_obj { struct kobject kobj; struct usb_device *usb_device; + u16 reg_addr; }; #define to_dci_obj(p) container_of(p, struct most_dci_obj, kobj) +struct most_dev; + +struct clear_hold_work { + struct work_struct ws; + struct most_dev *mdev; + unsigned int channel; + int pipe; +}; + +#define to_clear_hold_work(w) container_of(w, struct clear_hold_work, ws) + /** * struct most_dev - holds all usb interface specific stuff * @parent: parent object in sysfs @@ -104,10 +102,10 @@ struct most_dci_obj { * @link_stat: link status of hardware * @description: device description * @suffix: suffix for channel name - * @anchor_list_lock: locks list access + * @channel_lock: synchronize channel access * @padding_active: indicates channel uses padding * @is_channel_healthy: health status table of each channel - * @anchor_list: list of anchored items + * @busy_urbs: list of anchored items * @io_mutex: synchronize I/O with disconnect * @link_stat_timer: timer for link status reports * @poll_work_obj: work for polling link status @@ -124,10 +122,11 @@ struct most_dev { u16 link_stat; char description[MAX_STRING_LEN]; char suffix[MAX_NUM_ENDPOINTS][MAX_SUFFIX_LEN]; - spinlock_t anchor_list_lock[MAX_NUM_ENDPOINTS]; + spinlock_t channel_lock[MAX_NUM_ENDPOINTS]; /* sync channel access */ bool padding_active[MAX_NUM_ENDPOINTS]; bool is_channel_healthy[MAX_NUM_ENDPOINTS]; - struct list_head *anchor_list; + struct clear_hold_work clear_work[MAX_NUM_ENDPOINTS]; + struct usb_anchor *busy_urbs; struct mutex io_mutex; struct timer_list link_stat_timer; struct work_struct poll_work_obj; @@ -191,40 +190,24 @@ static inline int drci_wr_reg(struct usb_device *dev, u16 reg, u16 data) * free_anchored_buffers - free device's anchored items * @mdev: the device * @channel: channel ID + * @status: status of MBO termination */ -static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel) +static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel, + enum mbo_status_flags status) { struct mbo *mbo; - struct buf_anchor *anchor, *tmp; - unsigned long flags; + struct urb *urb; - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel], - list) { - struct urb *urb = anchor->urb; - - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - if (likely(urb)) { - mbo = urb->context; - if (!irqs_disabled()) { - usb_kill_urb(urb); - } else { - usb_unlink_urb(urb); - wait_for_completion(&anchor->urb_compl); - } - if ((mbo) && (mbo->complete)) { - mbo->status = MBO_E_CLOSE; - mbo->processed_length = 0; - mbo->complete(mbo); - } - usb_free_urb(urb); + while ((urb = usb_get_from_anchor(&mdev->busy_urbs[channel]))) { + mbo = urb->context; + usb_kill_urb(urb); + if (mbo && mbo->complete) { + mbo->status = status; + mbo->processed_length = 0; + mbo->complete(mbo); } - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_del(&anchor->list); - cancel_work_sync(&anchor->clear_work_obj); - kfree(anchor); + usb_free_urb(urb); } - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); } /** @@ -241,7 +224,7 @@ static unsigned int get_stream_frame_size(struct most_channel_config *cfg) return frame_size; } switch (cfg->data_type) { - case MOST_CH_ISOC_AVP: + case MOST_CH_ISOC: frame_size = AV_PACKETS_PER_XACT * sub_size; break; case MOST_CH_SYNC: @@ -274,22 +257,28 @@ static unsigned int get_stream_frame_size(struct most_channel_config *cfg) */ static int hdm_poison_channel(struct most_interface *iface, int channel) { - struct most_dev *mdev; + struct most_dev *mdev = to_mdev(iface); + unsigned long flags; + spinlock_t *lock; /* temp. lock */ - mdev = to_mdev(iface); if (unlikely(!iface)) { dev_warn(&mdev->usb_device->dev, "Poison: Bad interface.\n"); return -EIO; } - if (unlikely((channel < 0) || (channel >= iface->num_channels))) { + if (unlikely(channel < 0 || channel >= iface->num_channels)) { dev_warn(&mdev->usb_device->dev, "Channel ID out of range.\n"); return -ECHRNG; } + lock = mdev->channel_lock + channel; + spin_lock_irqsave(lock, flags); mdev->is_channel_healthy[channel] = false; + spin_unlock_irqrestore(lock, flags); + + cancel_work_sync(&mdev->clear_work[channel].ws); mutex_lock(&mdev->io_mutex); - free_anchored_buffers(mdev, channel); + free_anchored_buffers(mdev, channel, MBO_E_CLOSE); if (mdev->padding_active[channel]) mdev->padding_active[channel] = false; @@ -313,10 +302,10 @@ static int hdm_poison_channel(struct most_interface *iface, int channel) static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) { struct most_channel_config *conf = &mdev->conf[channel]; - unsigned int j, num_frames, frame_size; + unsigned int frame_size = get_stream_frame_size(conf); + unsigned int j, num_frames; u16 rd_addr, wr_addr; - frame_size = get_stream_frame_size(conf); if (!frame_size) return -EIO; num_frames = mbo->buffer_length / frame_size; @@ -350,10 +339,10 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) static int hdm_remove_padding(struct most_dev *mdev, int channel, struct mbo *mbo) { - unsigned int j, num_frames, frame_size; struct most_channel_config *const conf = &mdev->conf[channel]; + unsigned int frame_size = get_stream_frame_size(conf); + unsigned int j, num_frames; - frame_size = get_stream_frame_size(conf); if (!frame_size) return -EIO; num_frames = mbo->processed_length / USB_MTU; @@ -380,37 +369,29 @@ static int hdm_remove_padding(struct most_dev *mdev, int channel, */ static void hdm_write_completion(struct urb *urb) { - struct mbo *mbo; - struct buf_anchor *anchor; - struct most_dev *mdev; - struct device *dev; - unsigned int channel; + struct mbo *mbo = urb->context; + struct most_dev *mdev = to_mdev(mbo->ifp); + unsigned int channel = mbo->hdm_channel_id; + struct device *dev = &mdev->usb_device->dev; + spinlock_t *lock = mdev->channel_lock + channel; unsigned long flags; - mbo = urb->context; - anchor = mbo->priv; - mdev = to_mdev(mbo->ifp); - channel = mbo->hdm_channel_id; - dev = &mdev->usb_device->dev; - - if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || - (!mdev->is_channel_healthy[channel])) { - complete(&anchor->urb_compl); + spin_lock_irqsave(lock, flags); + if (urb->status == -ENOENT || urb->status == -ECONNRESET || + !mdev->is_channel_healthy[channel]) { + spin_unlock_irqrestore(lock, flags); return; } - if (unlikely(urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN))) { + if (unlikely(urb->status && urb->status != -ESHUTDOWN)) { mbo->processed_length = 0; switch (urb->status) { case -EPIPE: dev_warn(dev, "Broken OUT pipe detected\n"); - most_stop_enqueue(&mdev->iface, channel); - mbo->status = MBO_E_INVAL; - usb_unlink_urb(urb); - INIT_WORK(&anchor->clear_work_obj, wq_clear_halt); - schedule_work(&anchor->clear_work_obj); + mdev->is_channel_healthy[channel] = false; + spin_unlock_irqrestore(lock, flags); + mdev->clear_work[channel].pipe = urb->pipe; + schedule_work(&mdev->clear_work[channel].ws); return; case -ENODEV: case -EPROTO: @@ -425,10 +406,7 @@ static void hdm_write_completion(struct urb *urb) mbo->processed_length = urb->actual_length; } - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_del(&anchor->list); - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - kfree(anchor); + spin_unlock_irqrestore(lock, flags); if (likely(mbo->complete)) mbo->complete(mbo); @@ -545,36 +523,29 @@ static void hdm_write_completion(struct urb *urb) */ static void hdm_read_completion(struct urb *urb) { - struct mbo *mbo; - struct buf_anchor *anchor; - struct most_dev *mdev; - struct device *dev; + struct mbo *mbo = urb->context; + struct most_dev *mdev = to_mdev(mbo->ifp); + unsigned int channel = mbo->hdm_channel_id; + struct device *dev = &mdev->usb_device->dev; + spinlock_t *lock = mdev->channel_lock + channel; unsigned long flags; - unsigned int channel; - - mbo = urb->context; - anchor = mbo->priv; - mdev = to_mdev(mbo->ifp); - channel = mbo->hdm_channel_id; - dev = &mdev->usb_device->dev; - if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || - (!mdev->is_channel_healthy[channel])) { - complete(&anchor->urb_compl); + spin_lock_irqsave(lock, flags); + if (urb->status == -ENOENT || urb->status == -ECONNRESET || + !mdev->is_channel_healthy[channel]) { + spin_unlock_irqrestore(lock, flags); return; } - if (unlikely(urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN))) { + if (unlikely(urb->status && urb->status != -ESHUTDOWN)) { mbo->processed_length = 0; switch (urb->status) { case -EPIPE: dev_warn(dev, "Broken IN pipe detected\n"); - mbo->status = MBO_E_INVAL; - usb_unlink_urb(urb); - INIT_WORK(&anchor->clear_work_obj, wq_clear_halt); - schedule_work(&anchor->clear_work_obj); + mdev->is_channel_healthy[channel] = false; + spin_unlock_irqrestore(lock, flags); + mdev->clear_work[channel].pipe = urb->pipe; + schedule_work(&mdev->clear_work[channel].ws); return; case -ENODEV: case -EPROTO: @@ -588,21 +559,15 @@ static void hdm_read_completion(struct urb *urb) } } else { mbo->processed_length = urb->actual_length; - if (!mdev->padding_active[channel]) { - mbo->status = MBO_SUCCESS; - } else { - if (hdm_remove_padding(mdev, channel, mbo)) { - mbo->processed_length = 0; - mbo->status = MBO_E_INVAL; - } else { - mbo->status = MBO_SUCCESS; - } + mbo->status = MBO_SUCCESS; + if (mdev->padding_active[channel] && + hdm_remove_padding(mdev, channel, mbo)) { + mbo->processed_length = 0; + mbo->status = MBO_E_INVAL; } } - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_del(&anchor->list); - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - kfree(anchor); + + spin_unlock_irqrestore(lock, flags); if (likely(mbo->complete)) mbo->complete(mbo); @@ -628,18 +593,16 @@ static int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) { struct most_dev *mdev; - struct buf_anchor *anchor; struct most_channel_config *conf; struct device *dev; int retval = 0; struct urb *urb; - unsigned long flags; unsigned long length; void *virt_address; if (unlikely(!iface || !mbo)) return -EIO; - if (unlikely(iface->num_channels <= channel) || (channel < 0)) + if (unlikely(iface->num_channels <= channel || channel < 0)) return -ECHRNG; mdev = to_mdev(iface); @@ -650,32 +613,15 @@ static int hdm_enqueue(struct most_interface *iface, int channel, return -ENODEV; urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_ATOMIC); - if (!urb) { - dev_err(dev, "Failed to allocate URB\n"); + if (!urb) return -ENOMEM; - } - anchor = kzalloc(sizeof(*anchor), GFP_ATOMIC); - if (!anchor) { - retval = -ENOMEM; + if ((conf->direction & MOST_CH_TX) && mdev->padding_active[channel] && + hdm_add_padding(mdev, channel, mbo)) { + retval = -EIO; goto _error; } - anchor->urb = urb; - init_completion(&anchor->urb_compl); - mbo->priv = anchor; - - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_add_tail(&anchor->list, &mdev->anchor_list[channel]); - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - - if ((mdev->padding_active[channel]) && - (conf->direction & MOST_CH_TX)) - if (hdm_add_padding(mdev, channel, mbo)) { - retval = -EIO; - goto _error_1; - } - urb->transfer_dma = mbo->bus_address; virt_address = mbo->virt_address; length = mbo->buffer_length; @@ -688,7 +634,7 @@ static int hdm_enqueue(struct most_interface *iface, int channel, length, hdm_write_completion, mbo); - if (conf->data_type != MOST_CH_ISOC_AVP) + if (conf->data_type != MOST_CH_ISOC) urb->transfer_flags |= URB_ZERO_PACKET; } else { usb_fill_bulk_urb(urb, mdev->usb_device, @@ -701,6 +647,8 @@ static int hdm_enqueue(struct most_interface *iface, int channel, } urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &mdev->busy_urbs[channel]); + retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { dev_err(dev, "URB submit failed with error %d.\n", retval); @@ -709,10 +657,7 @@ static int hdm_enqueue(struct most_interface *iface, int channel, return 0; _error_1: - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_del(&anchor->list); - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - kfree(anchor); + usb_unanchor_urb(urb); _error: usb_free_urb(urb); return retval; @@ -731,29 +676,30 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, unsigned int frame_size; unsigned int temp_size; unsigned int tail_space; - struct most_dev *mdev; - struct device *dev; + struct most_dev *mdev = to_mdev(iface); + struct device *dev = &mdev->usb_device->dev; - mdev = to_mdev(iface); mdev->is_channel_healthy[channel] = true; - dev = &mdev->usb_device->dev; + mdev->clear_work[channel].channel = channel; + mdev->clear_work[channel].mdev = mdev; + INIT_WORK(&mdev->clear_work[channel].ws, wq_clear_halt); if (unlikely(!iface || !conf)) { dev_err(dev, "Bad interface or config pointer.\n"); return -EINVAL; } - if (unlikely((channel < 0) || (channel >= iface->num_channels))) { + if (unlikely(channel < 0 || channel >= iface->num_channels)) { dev_err(dev, "Channel ID out of range.\n"); return -EINVAL; } - if ((!conf->num_buffers) || (!conf->buffer_size)) { + if (!conf->num_buffers || !conf->buffer_size) { dev_err(dev, "Misconfig: buffer size or #buffers zero.\n"); return -EINVAL; } - if (!(conf->data_type == MOST_CH_SYNC) && - !((conf->data_type == MOST_CH_ISOC_AVP) && - (conf->packets_per_xact != 0xFF))) { + if (conf->data_type != MOST_CH_SYNC && + !(conf->data_type == MOST_CH_ISOC && + conf->packets_per_xact != 0xFF)) { mdev->padding_active[channel] = false; goto exit; } @@ -762,7 +708,7 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, temp_size = conf->buffer_size; frame_size = get_stream_frame_size(conf); - if ((frame_size == 0) || (frame_size > USB_MTU)) { + if (frame_size == 0 || frame_size > USB_MTU) { dev_warn(dev, "Misconfig: frame size wrong\n"); return -EINVAL; } @@ -807,17 +753,17 @@ static int hdm_update_netinfo(struct most_dev *mdev) if (!is_valid_ether_addr(mdev->hw_addr)) { if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_HI, &hi) < 0) { dev_err(dev, "Vendor request \"hw_addr_hi\" failed\n"); - return -1; + return -EFAULT; } if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_MI, &mi) < 0) { dev_err(dev, "Vendor request \"hw_addr_mid\" failed\n"); - return -1; + return -EFAULT; } if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_LO, &lo) < 0) { dev_err(dev, "Vendor request \"hw_addr_low\" failed\n"); - return -1; + return -EFAULT; } mutex_lock(&mdev->io_mutex); @@ -832,7 +778,7 @@ static int hdm_update_netinfo(struct most_dev *mdev) if (drci_rd_reg(usb_device, DRCI_REG_NI_STATE, &link) < 0) { dev_err(dev, "Vendor request \"link status\" failed\n"); - return -1; + return -EFAULT; } mutex_lock(&mdev->io_mutex); @@ -886,25 +832,22 @@ static void link_stat_timer_handler(unsigned long data) */ static void wq_netinfo(struct work_struct *wq_obj) { - struct most_dev *mdev; - int i, prev_link_stat; + struct most_dev *mdev = to_mdev_from_work(wq_obj); + int i, prev_link_stat = mdev->link_stat; u8 prev_hw_addr[6]; - mdev = to_mdev_from_work(wq_obj); - prev_link_stat = mdev->link_stat; - for (i = 0; i < 6; i++) prev_hw_addr[i] = mdev->hw_addr[i]; if (hdm_update_netinfo(mdev) < 0) return; - if ((prev_link_stat != mdev->link_stat) || - (prev_hw_addr[0] != mdev->hw_addr[0]) || - (prev_hw_addr[1] != mdev->hw_addr[1]) || - (prev_hw_addr[2] != mdev->hw_addr[2]) || - (prev_hw_addr[3] != mdev->hw_addr[3]) || - (prev_hw_addr[4] != mdev->hw_addr[4]) || - (prev_hw_addr[5] != mdev->hw_addr[5])) + if (prev_link_stat != mdev->link_stat || + prev_hw_addr[0] != mdev->hw_addr[0] || + prev_hw_addr[1] != mdev->hw_addr[1] || + prev_hw_addr[2] != mdev->hw_addr[2] || + prev_hw_addr[3] != mdev->hw_addr[3] || + prev_hw_addr[4] != mdev->hw_addr[4] || + prev_hw_addr[5] != mdev->hw_addr[5]) most_deliver_netinfo(&mdev->iface, mdev->link_stat, &mdev->hw_addr[0]); } @@ -917,33 +860,20 @@ static void wq_netinfo(struct work_struct *wq_obj) */ static void wq_clear_halt(struct work_struct *wq_obj) { - struct buf_anchor *anchor; - struct most_dev *mdev; - struct mbo *mbo; - struct urb *urb; - unsigned int channel; - unsigned long flags; + struct clear_hold_work *clear_work = to_clear_hold_work(wq_obj); + struct most_dev *mdev = clear_work->mdev; + unsigned int channel = clear_work->channel; + int pipe = clear_work->pipe; - anchor = to_buf_anchor(wq_obj); - urb = anchor->urb; - mbo = urb->context; - mdev = to_mdev(mbo->ifp); - channel = mbo->hdm_channel_id; - - if (usb_clear_halt(urb->dev, urb->pipe)) + mutex_lock(&mdev->io_mutex); + most_stop_enqueue(&mdev->iface, channel); + free_anchored_buffers(mdev, channel, MBO_E_INVAL); + if (usb_clear_halt(mdev->usb_device, pipe)) dev_warn(&mdev->usb_device->dev, "Failed to reset endpoint.\n"); - usb_free_urb(urb); - spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); - list_del(&anchor->list); - spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); - - if (likely(mbo->complete)) - mbo->complete(mbo); - if (mdev->conf[channel].direction & MOST_CH_TX) - most_resume_enqueue(&mdev->iface, channel); - - kfree(anchor); + mdev->is_channel_healthy[channel] = true; + most_resume_enqueue(&mdev->iface, channel); + mutex_unlock(&mdev->io_mutex); } /** @@ -958,7 +888,9 @@ static const struct file_operations hdm_usb_fops = { */ static struct usb_device_id usbid[] = { { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, - { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_INIC), }, + { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81118), }, + { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81119), }, + { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81210), }, { } /* Terminating entry */ }; @@ -970,6 +902,10 @@ static struct usb_device_id usbid[] = { struct most_dci_attribute most_dci_attr_##_name = \ __ATTR(_name, S_IRUGO | S_IWUSR, show_value, store_value) +#define MOST_DCI_WO_ATTR(_name) \ + struct most_dci_attribute most_dci_attr_##_name = \ + __ATTR(_name, S_IWUSR, NULL, store_value) + /** * struct most_dci_attribute - to access the attributes of a dci object * @attr: attributes of a dci object @@ -1046,45 +982,68 @@ static void most_dci_release(struct kobject *kobj) kfree(dci_obj); } +struct regs { + const char *name; + u16 reg; +}; + +static const struct regs ro_regs[] = { + { "ni_state", DRCI_REG_NI_STATE }, + { "packet_bandwidth", DRCI_REG_PACKET_BW }, + { "node_address", DRCI_REG_NODE_ADDR }, + { "node_position", DRCI_REG_NODE_POS }, +}; + +static const struct regs rw_regs[] = { + { "mep_filter", DRCI_REG_MEP_FILTER }, + { "mep_hash0", DRCI_REG_HASH_TBL0 }, + { "mep_hash1", DRCI_REG_HASH_TBL1 }, + { "mep_hash2", DRCI_REG_HASH_TBL2 }, + { "mep_hash3", DRCI_REG_HASH_TBL3 }, + { "mep_eui48_hi", DRCI_REG_HW_ADDR_HI }, + { "mep_eui48_mi", DRCI_REG_HW_ADDR_MI }, + { "mep_eui48_lo", DRCI_REG_HW_ADDR_LO }, +}; + +static int get_stat_reg_addr(const struct regs *regs, int size, + const char *name, u16 *reg_addr) +{ + int i; + + for (i = 0; i < size; i++) { + if (!strcmp(name, regs[i].name)) { + *reg_addr = regs[i].reg; + return 0; + } + } + return -EFAULT; +} + +#define get_static_reg_addr(regs, name, reg_addr) \ + get_stat_reg_addr(regs, ARRAY_SIZE(regs), name, reg_addr) + static ssize_t show_value(struct most_dci_obj *dci_obj, struct most_dci_attribute *attr, char *buf) { - u16 tmp_val; + const char *name = attr->attr.name; + u16 val; u16 reg_addr; int err; - if (!strcmp(attr->attr.name, "ni_state")) - reg_addr = DRCI_REG_NI_STATE; - else if (!strcmp(attr->attr.name, "packet_bandwidth")) - reg_addr = DRCI_REG_PACKET_BW; - else if (!strcmp(attr->attr.name, "node_address")) - reg_addr = DRCI_REG_NODE_ADDR; - else if (!strcmp(attr->attr.name, "node_position")) - reg_addr = DRCI_REG_NODE_POS; - else if (!strcmp(attr->attr.name, "mep_filter")) - reg_addr = DRCI_REG_MEP_FILTER; - else if (!strcmp(attr->attr.name, "mep_hash0")) - reg_addr = DRCI_REG_HASH_TBL0; - else if (!strcmp(attr->attr.name, "mep_hash1")) - reg_addr = DRCI_REG_HASH_TBL1; - else if (!strcmp(attr->attr.name, "mep_hash2")) - reg_addr = DRCI_REG_HASH_TBL2; - else if (!strcmp(attr->attr.name, "mep_hash3")) - reg_addr = DRCI_REG_HASH_TBL3; - else if (!strcmp(attr->attr.name, "mep_eui48_hi")) - reg_addr = DRCI_REG_HW_ADDR_HI; - else if (!strcmp(attr->attr.name, "mep_eui48_mi")) - reg_addr = DRCI_REG_HW_ADDR_MI; - else if (!strcmp(attr->attr.name, "mep_eui48_lo")) - reg_addr = DRCI_REG_HW_ADDR_LO; - else - return -EIO; + if (!strcmp(name, "arb_address")) + return snprintf(buf, PAGE_SIZE, "%04x\n", dci_obj->reg_addr); + + if (!strcmp(name, "arb_value")) + reg_addr = dci_obj->reg_addr; + else if (get_static_reg_addr(ro_regs, name, ®_addr) && + get_static_reg_addr(rw_regs, name, ®_addr)) + return -EFAULT; - err = drci_rd_reg(dci_obj->usb_device, reg_addr, &tmp_val); + err = drci_rd_reg(dci_obj->usb_device, reg_addr, &val); if (err < 0) return err; - return snprintf(buf, PAGE_SIZE, "%04x\n", tmp_val); + return snprintf(buf, PAGE_SIZE, "%04x\n", val); } static ssize_t store_value(struct most_dci_obj *dci_obj, @@ -1093,31 +1052,28 @@ static ssize_t store_value(struct most_dci_obj *dci_obj, { u16 val; u16 reg_addr; - int err; - - if (!strcmp(attr->attr.name, "mep_filter")) - reg_addr = DRCI_REG_MEP_FILTER; - else if (!strcmp(attr->attr.name, "mep_hash0")) - reg_addr = DRCI_REG_HASH_TBL0; - else if (!strcmp(attr->attr.name, "mep_hash1")) - reg_addr = DRCI_REG_HASH_TBL1; - else if (!strcmp(attr->attr.name, "mep_hash2")) - reg_addr = DRCI_REG_HASH_TBL2; - else if (!strcmp(attr->attr.name, "mep_hash3")) - reg_addr = DRCI_REG_HASH_TBL3; - else if (!strcmp(attr->attr.name, "mep_eui48_hi")) - reg_addr = DRCI_REG_HW_ADDR_HI; - else if (!strcmp(attr->attr.name, "mep_eui48_mi")) - reg_addr = DRCI_REG_HW_ADDR_MI; - else if (!strcmp(attr->attr.name, "mep_eui48_lo")) - reg_addr = DRCI_REG_HW_ADDR_LO; - else - return -EIO; + const char *name = attr->attr.name; + int err = kstrtou16(buf, 16, &val); - err = kstrtou16(buf, 16, &val); if (err) return err; + if (!strcmp(name, "arb_address")) { + dci_obj->reg_addr = val; + return count; + } + + if (!strcmp(name, "arb_value")) { + reg_addr = dci_obj->reg_addr; + } else if (!strcmp(name, "sync_ep")) { + u16 ep = val; + + reg_addr = DRCI_REG_BASE + DRCI_COMMAND + ep * 16; + val = 1; + } else if (get_static_reg_addr(ro_regs, name, ®_addr)) { + return -EFAULT; + } + err = drci_wr_reg(dci_obj->usb_device, reg_addr, val); if (err < 0) return err; @@ -1129,6 +1085,7 @@ static MOST_DCI_RO_ATTR(ni_state); static MOST_DCI_RO_ATTR(packet_bandwidth); static MOST_DCI_RO_ATTR(node_address); static MOST_DCI_RO_ATTR(node_position); +static MOST_DCI_WO_ATTR(sync_ep); static MOST_DCI_ATTR(mep_filter); static MOST_DCI_ATTR(mep_hash0); static MOST_DCI_ATTR(mep_hash1); @@ -1137,6 +1094,8 @@ static MOST_DCI_ATTR(mep_hash3); static MOST_DCI_ATTR(mep_eui48_hi); static MOST_DCI_ATTR(mep_eui48_mi); static MOST_DCI_ATTR(mep_eui48_lo); +static MOST_DCI_ATTR(arb_address); +static MOST_DCI_ATTR(arb_value); /** * most_dci_def_attrs - array of default attribute files of the dci object @@ -1146,6 +1105,7 @@ static struct attribute *most_dci_def_attrs[] = { &most_dci_attr_packet_bandwidth.attr, &most_dci_attr_node_address.attr, &most_dci_attr_node_position.attr, + &most_dci_attr_sync_ep.attr, &most_dci_attr_mep_filter.attr, &most_dci_attr_mep_hash0.attr, &most_dci_attr_mep_hash1.attr, @@ -1154,6 +1114,8 @@ static struct attribute *most_dci_def_attrs[] = { &most_dci_attr_mep_eui48_hi.attr, &most_dci_attr_mep_eui48_mi.attr, &most_dci_attr_mep_eui48_lo.attr, + &most_dci_attr_arb_address.attr, + &most_dci_attr_arb_value.attr, NULL, }; @@ -1176,10 +1138,9 @@ static struct kobj_type most_dci_ktype = { static struct most_dci_obj *create_most_dci_obj(struct kobject *parent) { - struct most_dci_obj *most_dci; + struct most_dci_obj *most_dci = kzalloc(sizeof(*most_dci), GFP_KERNEL); int retval; - most_dci = kzalloc(sizeof(*most_dci), GFP_KERNEL); if (!most_dci) return NULL; @@ -1216,21 +1177,17 @@ static void destroy_most_dci_obj(struct most_dci_obj *p) static int hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) { + struct usb_host_interface *usb_iface_desc = interface->cur_altsetting; + struct usb_device *usb_dev = interface_to_usbdev(interface); + struct device *dev = &usb_dev->dev; + struct most_dev *mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); unsigned int i; unsigned int num_endpoints; struct most_channel_capability *tmp_cap; - struct most_dev *mdev; - struct usb_device *usb_dev; - struct device *dev; - struct usb_host_interface *usb_iface_desc; struct usb_endpoint_descriptor *ep_desc; int ret = 0; int err; - usb_iface_desc = interface->cur_altsetting; - usb_dev = interface_to_usbdev(interface); - dev = &usb_dev->dev; - mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) goto exit_ENOMEM; @@ -1276,9 +1233,9 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) if (!mdev->ep_address) goto exit_free2; - mdev->anchor_list = - kcalloc(num_endpoints, sizeof(*mdev->anchor_list), GFP_KERNEL); - if (!mdev->anchor_list) + mdev->busy_urbs = + kcalloc(num_endpoints, sizeof(*mdev->busy_urbs), GFP_KERNEL); + if (!mdev->busy_urbs) goto exit_free3; tmp_cap = mdev->cap; @@ -1297,21 +1254,21 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) tmp_cap->num_buffers_packet = BUF_CHAIN_SIZE; tmp_cap->num_buffers_streaming = BUF_CHAIN_SIZE; tmp_cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | - MOST_CH_ISOC_AVP | MOST_CH_SYNC; + MOST_CH_ISOC | MOST_CH_SYNC; if (usb_endpoint_dir_in(ep_desc)) tmp_cap->direction = MOST_CH_RX; else tmp_cap->direction = MOST_CH_TX; tmp_cap++; - INIT_LIST_HEAD(&mdev->anchor_list[i]); - spin_lock_init(&mdev->anchor_list_lock[i]); + init_usb_anchor(&mdev->busy_urbs[i]); + spin_lock_init(&mdev->channel_lock[i]); err = drci_wr_reg(usb_dev, DRCI_REG_BASE + DRCI_COMMAND + ep_desc->bEndpointAddress * 16, 1); if (err < 0) - pr_warn("DCI Sync for EP %02x failed", - ep_desc->bEndpointAddress); + dev_warn(dev, "DCI Sync for EP %02x failed", + ep_desc->bEndpointAddress); } dev_notice(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x\n", le16_to_cpu(usb_dev->descriptor.idVendor), @@ -1332,7 +1289,9 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) } mutex_lock(&mdev->io_mutex); - if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_INIC) { + if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 || + le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81119 || + le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81210) { /* this increments the reference count of the instance * object of the core */ @@ -1351,7 +1310,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) return 0; exit_free4: - kfree(mdev->anchor_list); + kfree(mdev->busy_urbs); exit_free3: kfree(mdev->ep_address); exit_free2: @@ -1379,9 +1338,8 @@ exit_ENOMEM: */ static void hdm_disconnect(struct usb_interface *interface) { - struct most_dev *mdev; + struct most_dev *mdev = usb_get_intfdata(interface); - mdev = usb_get_intfdata(interface); mutex_lock(&mdev->io_mutex); usb_set_intfdata(interface, NULL); mdev->usb_device = NULL; @@ -1393,7 +1351,7 @@ static void hdm_disconnect(struct usb_interface *interface) destroy_most_dci_obj(mdev->dci); most_deregister_interface(&mdev->iface); - kfree(mdev->anchor_list); + kfree(mdev->busy_urbs); kfree(mdev->cap); kfree(mdev->conf); kfree(mdev->ep_address); |