Hi! > > The TODO file says: > > > > # > + > > # > + skb_queue_tail(&info->txq, fw_skb); > > # > + spin_lock_irqsave(&info->lock, flags); > > # > + hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | > > # > + UART_IER_THRI); > > # > + spin_unlock_irqrestore(&info->lock, flags); > > # > +} > > # > > # and as I explained before, this crazy can not continue. Bluetooth drivers > > can provide a > > # +hdev->setup callback for loading firmware and doing other setup details. > > You can just > > # +bring up the HCI transport. We are providing __hci_cmd_sync for easy > > loading of the > > # +firmware. Especially if the firmware just consists of HCI commands. > > Which is clearly the > > # +case with the Nokia firmware files. > > > > ...so I take it you (and thus TODO) were wrong and __hci_cmd_sync is > > not suitable after all? > > __hci_cmd_sync is to be used in hdev->setup where you load the firmware. > However when hdev->setup is run, we expect that the HCI transport is fully up > and running and that the driver takes care of the transport. That is done via > hdev->send and hci_recv_frame. >
h4p changes uart speed again after load of the firmware, but I guess that's ok. > > But I don't understand what you want me to do at this point. I guess > > skb_queue_tail+hci_h4p_outb should be moved to a helper function > > (that's easy), and I already moved initialization to hci_setup(). > > > > nokia_core.c uses test_bit(HCI_RUNNING, &info->hdev->flags) to tell > > between initialization and data traffic, but I guess that's fine? > > I have no idea on how much more I can explain this. There should be code in > the driver that handles the HCI transport. That means init of the transport > and sending and receiving HCI frames. And then there is the piece to load the > firmware etc. These are two independent things. > Ok, it looks like __hci_cmd_sync() is indeed good match for the firmware load. > > What needs to be done is the bring up of the device including the proper UART > settings and speed and then just run the firmware downloads. All firmware > files on the Nokia devices where just HCI commands with vendor specific > details. Some from CSR, some from Broadcom and some from TI. You can actually > decode them if you really want to. Shouldn't be that hard. > Speed changes at the end of firmware load, but I guess that's detail? Anyway, patch would look like this. diff --git a/drivers/staging/nokia_h4p/nokia_core.c b/drivers/staging/nokia_h4p/nokia_core.c index 9ece2c8..5cdb86a 100644 --- a/drivers/staging/nokia_h4p/nokia_core.c +++ b/drivers/staging/nokia_h4p/nokia_core.c @@ -475,12 +475,6 @@ static inline void hci_h4p_recv_frame(struct hci_h4p_info *info, info->rx_state = WAIT_FOR_PKT_TYPE; return; } - - if (!test_bit(HCI_UP, &info->hdev->flags)) { - BT_DBG("fw_event"); - hci_h4p_parse_fw_event(info, skb); - return; - } } hci_recv_frame(info->hdev, skb); diff --git a/drivers/staging/nokia_h4p/nokia_fw-bcm.c b/drivers/staging/nokia_h4p/nokia_fw-bcm.c index 8066b21..89718d4 100644 --- a/drivers/staging/nokia_h4p/nokia_fw-bcm.c +++ b/drivers/staging/nokia_h4p/nokia_fw-bcm.c @@ -45,84 +45,17 @@ static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, return 0; } -void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) -{ - struct sk_buff *fw_skb; - int err; - unsigned long flags; - - if (skb->data[5] != 0x00) { - dev_err(info->dev, "Firmware sending command failed 0x%.2x\n", - skb->data[5]); - info->fw_error = -EPROTO; - } - - kfree_skb(skb); - - fw_skb = skb_dequeue(info->fw_q); - if (fw_skb == NULL || info->fw_error) { - complete(&info->fw_completion); - return; - } - - if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && - fw_skb->len >= 10) { - BT_DBG("Setting bluetooth address"); - err = hci_h4p_bcm_set_bdaddr(info, fw_skb); - if (err < 0) { - kfree_skb(fw_skb); - info->fw_error = err; - complete(&info->fw_completion); - return; - } - } - - hci_h4p_simple_send_frame(info, fw_skb); -} - - int hci_h4p_bcm_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) { - struct sk_buff *skb; - unsigned long flags, time; + unsigned long time; info->fw_error = 0; - BT_DBG("Sending firmware"); + printk("Sending firmware (not really)\n"); time = jiffies; - - info->fw_q = fw_queue; - skb = skb_dequeue(fw_queue); - if (!skb) - return -ENODATA; - - BT_DBG("Sending commands"); - - /* - * Disable smart-idle as UART TX interrupts - * are not wake-up capable - */ - hci_h4p_smart_idle(info, 0); - - /* Check if this is bd_address packet */ - init_completion(&info->fw_completion); - - hci_h4p_simple_send_frame(info, skb); - - if (!wait_for_completion_timeout(&info->fw_completion, - msecs_to_jiffies(2000))) { - dev_err(info->dev, "No reply to fw command\n"); - return -ETIMEDOUT; - } - - if (info->fw_error) { - dev_err(info->dev, "FW error\n"); - return -EPROTO; - } - - BT_DBG("Firmware sent in %d msecs", + printk("Firmware sent in %d msec\n", jiffies_to_msecs(jiffies-time)); hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); diff --git a/drivers/staging/nokia_h4p/nokia_fw.c b/drivers/staging/nokia_h4p/nokia_fw.c index b5748c8..be5f619 100644 --- a/drivers/staging/nokia_h4p/nokia_fw.c +++ b/drivers/staging/nokia_h4p/nokia_fw.c @@ -76,6 +72,7 @@ static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb, const struct firmware *fw_entry, gfp_t how) { unsigned int cmd_len; + static int num = 0; if (fw_pos >= fw_entry->size) return 0; @@ -95,16 +92,24 @@ static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb, return -EMSGSIZE; } - *skb = bt_skb_alloc(cmd_len, how); - if (!*skb) { - dev_err(info->dev, "Cannot reserve memory for buffer\n"); - return -ENOMEM; + /* Note that this is timing-critical. If sending packets takes too + long, initialization will fail. */ + printk("Packet %d...", num); + if (num > 1) { + int cmd = fw_entry->data[fw_pos+1] + (fw_entry->data[fw_pos+2] << 8); + int len = fw_entry->data[fw_pos+3]; + printk("cmd %x, len %d.", cmd, len); + *skb = __hci_cmd_sync(info->hdev, cmd, len, fw_entry->data+fw_pos+4, 500); + if (IS_ERR(*skb)) { + printk("...sending cmd failed %d\n", PTR_ERR(*skb)); + return -EIO; + } } - memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len); + num++; fw_pos += cmd_len; - return (*skb)->len; + return 1; } int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) @@ -113,31 +118,22 @@ int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) struct sk_buff *skb = NULL; int err; + /* + * Disable smart-idle as UART TX interrupts + * are not wake-up capable + */ + hci_h4p_smart_idle(info, 0); + err = hci_h4p_open_firmware(info, &fw_entry); if (err < 0 || !fw_entry) goto err_clean; + printk("read firmware\n"); + /* FIXME: remove skb... */ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) { - if (err < 0 || !skb) - goto err_clean; - - skb_queue_tail(fw_queue, skb); } - /* Chip detection code does neg and alive stuff - * discard two first skbs */ - skb = skb_dequeue(fw_queue); - if (!skb) { - err = -EMSGSIZE; - goto err_clean; - } - kfree_skb(skb); - skb = skb_dequeue(fw_queue); - if (!skb) { - err = -EMSGSIZE; - goto err_clean; - } - kfree_skb(skb); + printk("done read firmware\n"); err_clean: hci_h4p_close_firmware(fw_entry); @@ -160,20 +156,4 @@ int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) return err; } -void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) -{ - switch (info->man_id) { - case H4P_ID_BCM2048: - hci_h4p_bcm_parse_fw_event(info, skb); - break; - default: - dev_err(info->dev, "Don't know how to parse fw event\n"); - info->fw_error = -EINVAL; - } -} - -MODULE_FIRMWARE(FW_NAME_TI1271_PRELE); -MODULE_FIRMWARE(FW_NAME_TI1271_LE); -MODULE_FIRMWARE(FW_NAME_TI1271); MODULE_FIRMWARE(FW_NAME_BCM2048); -MODULE_FIRMWARE(FW_NAME_CSR); -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html