Краткий анализ драйвера WiFi интерфейса SDIO [легко понять]
Краткий анализ драйвера WiFi интерфейса SDIO [легко понять]

Модуль SDIO-Wifi представляет собой встроенный модуль на основе интерфейса SDIO, который соответствует стандартам беспроводной сети Wi-Fi. Он имеет встроенный стек протоколов беспроводной сети IEEE802.11 и стек протоколов TCP/IP, который может осуществлять связь между пользовательскими устройствами. данные основной платформы и беспроводную сеть через порт SDIO Convert. SDIO обладает характеристиками быстрой передачи данных и совместим с интерфейсами SD и MMC.

Для интерфейса SDIO WiFi, прежде всего, это устройство карты SDIO, а затем оно имеет функцию WiFi. Поэтому при регистрации вам следует сначала зарегистрировать его как устройство карты SDIO. Затем после обнаружения карты необходимо погонять ее функцию wifi. Очевидно, для управления ею она использует протокол sdio, отправляя команды и данные. Давайте кратко рассмотрим соответствующие знания SDIO:

1. Анализ базовых знаний, связанных с SDIO

1. Интерфейс SDIO

Как следует из названия, SDIO означает интерфейс ввода-вывода SD, но это объяснение может быть немного абстрактным. Если быть более конкретным, изначально SD была стандартом для карт памяти, но теперь SD также можно использовать, подключившись к некоторым периферийным интерфейсам. Эта технология называется SDIO.

Таким образом, сама SDIO представляет собой довольно простую технологию. Она подключается к внешним периферийным устройствам через контакты ввода-вывода SD и передает данные на эти периферийные устройства через интерфейсы данных ввода-вывода на SD. также представлено множество. Полный драйвер стека SDIO делает разработку и применение периферийных устройств SDIO (мы называем их SDIO-картами) очень популярными.

В настоящее время многие мобильные телефоны и портативные устройства поддерживают функции SDIO (стандарт SD изначально был сформулирован для мобильных устройств), а также было разработано множество периферийных устройств SDIO, что упрощает подключение внешних периферийных устройств для мобильных телефонов и делает разработку более эффективной. встроенная периферия не требуется). В настоящее время распространенными периферийными устройствами SDIO (картами SDIO) являются:

· Карта Wi-Fi (карта беспроводной сети)

· Сенсорная карта CMOS (модуль камеры)

· GPS card

· GSM/GPRS modem card

· Bluetooth card

Применение SDIO станет одной из наиболее важных интерфейсных технологий в будущих встроенных системах, а также заменит текущий интерфейс SPI в стиле GPIO.

2. Шина SDIO

Шина SDIO аналогична шине USB. SDIO также имеет два конца, один из которых является концом HOST, а другой — концом устройства. Вся связь начинается с отправки команд HOST. Пока Устройство может анализировать команду, оно может взаимодействовать друг с другом.

Сигнал CLK: тактовый сигнал, передаваемый HOST на DEVICE, передающий команду каждый такт.

Сигнал CMD: двунаправленный сигнал, используемый для передачи команд и ответов.

Сигналы DAT0-DAT3: четыре линии данных для передачи.

Сигнал VDD: сигнал мощности.

VSS1, VSS2: сигнал заземления питания.

3. Принцип горячей замены SDIO

Способ: настроить проверку таймера или обнаружение прерываний плагина.

Аппаратное обеспечение: если GPG10 (EINT18) используется для обнаружения SD-карты.

GPG10 высокого уровня, то есть SD-карта не вставлена.

GPG10 — низкий уровень, то есть SD-карта вставлена.

4. Команда SDIO

На шине SDIO сторона HOST инициирует запрос, а затем сторона DEVICE отвечает на запрос. Команда sdio состоит из 6 байт.

a — Команда: команда, используемая для начала передачи, отправляется от ХОСТА к УСТРОЙСТВУ. Команда передается по сигнальной линии CMD.

b — Ответ: ответом является команда HOST, возвращаемая УСТРОЙСТВОМ в качестве ответа на команду. Он также передается по линии CMD.

c - Данные: данные передаются в обоих направлениях. Его можно установить в 1-проводной или 4-проводной режим. Данные передаются через сигнальную линию DAT0-DAT3.

Каждая операция SDIO инициируется HOST в строке CMD. Для некоторых CMD DEVICE должен возвращать ответ, а для других — нет.

Для команды чтения сначала ХОСТ отправит команду УСТРОЙСТВУ, а затем УСТРОЙСТВО вернет сигнал подтверждения. В это время, когда ХОСТ получит ответный сигнал подтверждения, он поместит данные в 4-битные данные. За ней также будет следовать код проверки CRC. Когда вся передача чтения будет завершена, HOST снова отправит команду, чтобы уведомить DEVICE о завершении операции, и в то же время DEVICE вернет ответ.

Для команд записи сначала ХОСТ отправит команду УСТРОЙСТВУ, а затем УСТРОЙСТВО вернет сигнал подтверждения. В это время, когда ХОСТ получит ответный сигнал подтверждения, он поместит данные в 4-битную линию данных. За ним также будет следовать код проверки CRC. Когда вся передача записи будет завершена, HOST снова отправит команду, чтобы уведомить DEVICE о завершении операции, и в то же время DEVICE вернет ответ.

2. Драйвер интерфейса SDIO

Как упоминалось ранее, WiFi интерфейса SDIO — это, прежде всего, устройство карты SDIO, а затем оно имеет функцию WiFi, поэтому драйвер WiFi интерфейса SDIO помещает оболочку драйвера SDIO в драйвер WiFi, а Драйвер SDIO по-прежнему соответствует идеям многоуровневого и разделения драйверов устройств:

Уровень драйвера устройства (устройство Wi-Fi)

|

Базовый уровень (предоставление интерфейсов вверх и вниз)

|

Уровень хост-драйвера (реализующий драйвер SDIO)

Давайте сначала проанализируем реализацию драйвера интерфейса SDIO и рассмотрим несколько важных структур данных (используемых для обработки обмена данными между базовым уровнем и уровнем драйвера хоста).

[ /include/linux/mmc/host.h ]

struct mmc_host используется для описания контроллера карты.

struct mmc_card используется для описания карты

struct mmc_driver используется для описания драйвера карты mmc.

struct sdio_func используется для описания функциональных устройств

Структура mmc_host_ops используется для описания функциональной функции интерфейса работы контроллера карты и используется для регистрации рабочих функций с уровня хост-контроллера на базовый уровень, тем самым изолируя базовый уровень от конкретного хост-контроллера. Другими словами, если ядро ​​хочет управлять хост-контроллером, оно использует для работы указатель функции, указанный в этой операции, и не может напрямую вызвать функцию конкретного хост-контроллера.

Анализ драйверов уровня HOST в В предыдущей серии статей Linux Разработка драйвера SD-карты (2) —— SD Статья HOST об анализе драйверов карт Ниже приводится подробное объяснение некоторых важных функций обработки.

1. Напишите драйвер уровня хоста.

Ссылка здесь — драйвер HOST S3C24XX /drivers/mmc/host/s3cmci.c.

[cpp] view plain copy

  1. static struct platform_driver s3cmci_driver = {
  2. .driver = {
  3. .name = «s3c-sdi», //Соответствие имени и определения устройства платформы
  4. .owner = THIS_MODULE,
  5. .pm = s3cmci_pm_ops,
  6. },
  7. .id_table = s3cmci_driver_ids,
  8. .probe = s3cmci_probe, //Функция интерфейса обнаружения устройств платформы
  9. .remove = __devexit_p(s3cmci_remove),
  10. .shutdown = s3cmci_shutdown,
  11. };
  12. s3cmci_probe(struct platform_device *pdev)
  13. {
  14. //….
  15. struct mmc_host *mmc;
  16. mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); //Выделяем структуру mmc_host
  17. //…..
  18. }
  19. /*Регистрируем обработчик прерываний Functions3cmci_irq для обработки различных прерываний, вызванных процессом отправки и получения данных*/
  20. request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host) //Регистрируем функции обработки прерываний3cmci_irq
  21. /*Зарегистрируйте обработчик прерываний s3cmci_irq_cdфункцию для обработки прерываний, вызванных горячим подключением. Формат триггера прерывания: триггер по нарастающему или заднему фронту*/
  22. request_irq(host->irq_cd, s3cmci_irq_cd,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, DRIVER_NAME, host)
  23. mmc_add_host(mmc); //инициализируем оборудование хоста //Зарегистрируем драйвер хоста в ядре MMC
  24. —-> device_add(&host->class_dev); //Добавляем устройство в список устройств на шине mmc_bus_type
  25. —-> mmc_start_host(host); //Запускаем ммс host
  26. /*Драйверы MMC должны вызывать этот метод, когда обнаруживают, что карта была вставлена ​​или извлечена. Определить, была ли вставлена ​​или извлечена SD-карта*/
  27. —->mmc_detect_change(host, 0);
  28. /*Запланировать отложенную работу в рабочей очереди MMC. Запланировать отложенную рабочую очередь*/
  29. mmc_schedule_delayed_work(&host->detect, delay);

поискhost->detectedПолучите следующую информацию:

[/drivers/mmc/core/host.c]

[cpp] view plain copy

  1. NIT_DELAYED_WORK(&host->detect, mmc_rescan);
  2. mmc_rescan(struct work_struct *work)
  3. —->mmc_bus_put(host);//card При снятии с автобуса освободите занимаемое им место в автобусе.
  4. /*Оцениваем текущий mmc Занят ли хост-контроллер, если занят текущий контроллер mmc, то host->claimed = 1; иначе 0;
  5. *Если он равен 1, то в цикле while(1) будет вызвано расписание для отключения. Когда операция, занимающая контроллер MMC, будет завершена,выполните ее. *mmc_release_host()из времени,Активирую регистрацию наждать Ожидание в очереди&host->wqсерединаиздругой Программа получает право на использование основного контроллера mmc.
  6. */
  7. mmc_claim_host(host);
  8. mmc_rescan_try_freq(host, max(freqs[i], host->f_min);
  9. static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
  10. {
  11. /* Order’s important: probe SDIO, then SD, then MMC */
  12. if (!mmc_attach_sdio(host))
  13. return 0;
  14. if (!mmc_attach_sd(host))
  15. return 0;
  16. if (!mmc_attach_mmc(host))
  17. return 0;
  18. ….
  19. }
  20. mmc_attach_sdio(struct mmc_host *host) //Соответствие интерфейсной карте Sdio
  21. —>mmc_attach_bus(host, &mmc_sdio_ops);
  22. /*Когда карта соответствует водителю в автобусе, инициализируйте карту*/
  23. mmc_sdio_init_card(host, host->ocr, NULL, 0);
  24. —>card = mmc_alloc_card(host, NULL);//Выделяем структуру карты
  25. mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); //Устанавливаем рабочий режим mmc_bus;
  26. struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; //SDIO functions (devices)
  27. sdio_init_func(host->card, i + 1);
  28. —>func = sdio_alloc_func(card); //Выделяем структуру Структура sdio_fun (функциональное устройство sdio)
  29. mmc_io_rw_direct();
  30. card->sdio_func[fn – 1] = func;
  31. mmc_add_card(host->card); //Подключаем конкретное sdio-устройство к mmc_bus_types автобус
  32. sdio_add_func(host->card->sdio_func[i]); //Будет sdioфункциональное оборудованиемонтировать наsdio_bus_typesавтобус

Серия вызовов функций здесь была объяснена в предыдущем разделе «москитная сетка» драйвера SD и не будет подробно описываться.

2. Горячая замена SDIO-устройств.

При подключении и отключении устройств SDIO,Вызовет уведомление о прерывании процессора,Затем выполните функцию обработки прерывания обнаружения карты в этой функции службы прерываний.,mmc_detect_change->mmc_schedule_delayed_work(&host->detect,delay), INIT_DELAYED_WORK(&host->detect, mmc_rescan) запланирует функцию mmc_rescan для задержки рабочей очереди планирования, что также запустит процесс инициализации устройства SDIO. После обнаружения действительного устройства SDIO оно будет зарегистрировано в системе.

[cpp] view plain copy

  1. static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
  2. {
  3. struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
  4. ……..
  5. mmc_detect_change(host->mmc, msecs_to_jiffies(500));
  6. return IRQ_HANDLED;
  7. }

3. Частичный анализ драйвера Wi-Fi.

Универсальная программная архитектура, основанная на Wi-Fi

1. Он разделен на две части: верхняя часть — это драйвер хоста, а нижняя — это прошивка, о которой мы упоминали ранее.

2. Основная работа части прошивки такова: поскольку антенна принимает и отправляет обратно кадры 802.11, а данные, принимаемые и передаваемые хостом, должны быть кадрами 802.3, то прошивка должна отвечать за кадры 802.3 и переходные кадры 802.11. между кадрами

3. Когда антенна получит данные и обработает их прошивкой, они будут помещены в буфер, и после получения прерывания будет сгенерировано прерывание.

Драйвер устройства SDIO определяется структурой sdio_driver, а sdio_driver фактически является пакетом драйвера. Загрузка драйвера устройства SDIO в ядро ​​через функцию sdio_register_driver фактически монтирует его на шину sdio_bus_type.

1. Регистрация и сопоставление драйверов устройств.

[Drivers/net/wireless/libertas/if_sdio.c]

[cpp] view plain copy

  1. /* SDIO function device driver*/
  2. struct sdio_driver {
  3. char *name; //Имя устройства
  4. const struct sdio_device_id *id_table; //Идентификатор драйвера устройства
  5. int (*probe)(struct sdio_func *, const struct sdio_device_id *);//соответствоватьфункция
  6. void (*remove)(struct sdio_func *);
  7. struct device_driver drv;
  8. };

Далее следует наполнение конкретных функций:

[cpp] view plain copy

  1. /*if_sdio.c*/
  2. static struct sdio_driver if_sdio_driver = {
  3. .name = “libertas_sdio”,
  4. .id_table = if_sdio_ids, //используется для сопоставления устройств и драйверов
  5. .probe = if_sdio_probe,
  6. .remove = if_sdio_remove,
  7. .drv = {
  8. .pm = &if_sdio_pm_ops,
  9. }
  10. };

Функция регистрации устройства

[cpp] view plain copy

  1. /**
  2. * sdio_register_driver – register a function driver
  3. * @drv: SDIO function driver
  4. */
  5. int sdio_register_driver(struct sdio_driver *drv)
  6. {
  7. drv->drv.name = drv->name;
  8. drv->drv.bus = &sdio_bus_type; //Устанавливаем шину драйвера на sdio_bus_type
  9. return driver_register(&drv->drv);
  10. }

функция шины

[cpp] view plain copy

  1. static struct bus_type sdio_bus_type = {
  2. .name = “sdio”,
  3. .dev_attrs = sdio_dev_attrs,
  4. .match = sdio_bus_match,
  5. .uevent = sdio_bus_uevent,
  6. .probe = sdio_bus_probe,
  7. .remove = sdio_bus_remove,
  8. .pm = SDIO_PM_OPS_PTR,
  9. };

Примечание. В процессе регистрации устройства или драйвера в системе будет вызвана функция сопоставления на соответствующей шине для сопоставления соответствующего драйвера или устройства. Сопоставление устройств sdio завершается функциями sdio_bus_match и sdio_bus_probe.

[cpp] view plain copy

  1. static int sdio_bus_match(struct device *dev, struct device_driver *drv)
  2. {
  3. struct sdio_func *func = dev_to_sdio_func(dev);
  4. struct sdio_driver *sdrv = to_sdio_driver(drv);
  5. if (sdio_match_device(func, sdrv))
  6. return 1;
  7. return 0;
  8. }
  9. static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
  10. struct sdio_driver *sdrv)
  11. {
  12. const struct sdio_device_id *ids;
  13. ids = sdrv->id_table;
  14. if (sdio_match_one(func, ids))
  15. return ids;
  16. }

Судя по описанному выше процессу сопоставления, соответствующий драйвер или устройство сопоставляется путем сопоставления идентификатора в драйвере устройства id_table и sdio_driver. В конечном итоге будет вызвана функция .probe для завершения соответствующих операций.

2. Функция If_sdio_probe

при обнаруженииsdioОн будет вызван после того, как карта будет вставлена.If_sdio_probe,и будет вызван при извлечении картыIf_sdio_remove。

Давайте сначала посмотримIf_sdio_probetфункция,if_sdio_prob функция В основном делал две вещи

[cpp] view plain copy

  1. static struct sdio_driver if_sdio_driver = {
  2. .name = “libertas_sdio”,
  3. .id_table = if_sdio_ids, //используется для сопоставления устройств и драйверов
  4. .probe = if_sdio_probe,
  5. .remove = if_sdio_remove,
  6. .drv = {
  7. .pm = &if_sdio_pm_ops,
  8. },
  9. };
  10. 1 //Определение структуры карты if_sdio
  11. struct if_sdio_card *card;
  12. struct if_sdio_packet *packet; //sdio структура пакета
  13. struct mmc_host *host = func->card->host;
  14. // Проверяем, есть ли указанный функциональный регистр в mmc
  15. //_sdio_cardсередина
  16. for (i = 0;i < func->card->num_info;i++) {
  17. if (sscanf(func->card->info[i],
  18. “802.11 SDIO ID: %x”, &model) == 1)
  19. //Выполняем здесь выбор чипа и выбираем устройство Marvell 8686, которое мы используем.
  20. case MODEL_8686:
  21. card->scratch_reg = IF_SDIO_SCRATCH;
  22. //Создаем рабочую очередь sdio
  23. card->workqueue = create_workqueue(“libertas_sdio”);
  24. //Вызов ниже функции
  25. INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
  26. //Очередь работы от хоста к карте
  27. static void if_sdio_host_to_card_worker(struct work_struct *work)
  28. /* Проверяем, поддерживаем ли мы эту карту. Выберите тип карты, которую мы поддерживаем */
  29. //Назначаем значение sd8686_helper.bin sd8686.bin
  30. /*MOEL_8686, «sd8686_helper.bin», «sd8686.bin» в fw_table },?/
  31. for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
  32. if (card->model == fw_table[i].model)
  33. break;
  34. }
  35. { MODEL_8688, “libertas/sd8688_helper.bin”, “libertas/sd8688.bin” },
  36. //Подать заявку на хостинг
  37. sdio_claim_host(func);
  38. //Включаем регистр функции sdio
  39. ret = sdio_enable_func(func);
  40. if (ret)
  41. goto release;
  42. 2//Применить прерывание sdio и выполнить прерывание при наличии данных, команды или события.
  43. ret = sdio_claim_irq(func, if_sdio_interrupt);
  44. ret = if_sdio_card_to_host(card); //Данные, полученные от беспроводной сетевой карты, или сообщаемые данные
  45. ret = if_sdio_handle_data(card, card->buffer + 4, chunk – 4); //Обработка полученных данных
  46. ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk – 4); //Обработка запрошенного командного прерывания
  47. ret = if_sdio_handle_event(card, card->buffer + 4, chunk – 4);//Прерывание приложения обработки событий
  48. //Добавляем структуру сети, выделяем устройства и регистрируем
  49. priv = lbs_add_card(card, &func->dev);
  50. //Назначаем Ethernet-устройство и регистрируем
  51. wdev = lbs_cfg_alloc(dmdev);
  52. //беспроводная сеть 802, неспецифическая функция работы
  53. wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
  54. //Выделяемое сетевое оборудование частично эксплуатируется всей сетью
  55. //Основная структура
  56. dev = alloc_netdev(0, «wlan%d», ether_setup); //создаем экземпляр атрибутов wlan0;
  57. dev->ieee80211_ptr = wdev;
  58. dev->ml_priv = priv;
  59. //Установим физический адрес устройства
  60. SET_NETDEV_DEV(dev, dmdev);
  61. wdev->netdev = dev;
  62. priv->dev = dev;
  63. //Инициализируем сторожевой таймер сетевого устройства.
  64. dev->netdev_ops = &lbs_netdev_ops; //Независимая функция эксплуатации сетевого оборудования
  65. dev->watchdog_timeo = 5 * HZ;
  66. dev->ethtool_ops = &lbs_ethtool_ops;
  67. dev->flags |= IFF_BROADCAST | IFF_MULTICAST; //широковещательная или многоадресная рассылка
  68. //Запускаем поток ядра для управления этим сетевым устройством из Отправка данные, событие обработки (извлечение карты) и некоторая обработка заказа
  69. priv->main_thread = kthread_run(lbs_thread, dev, “lbs_main”);
  70. //Инициализируем связанные рабочие очереди
  71. priv->work_thread = create_singlethread_workqueue(“lbs_worker”);
  72. INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
  73. priv->wol_criteria = EHS_REMOVE_WAKEUP;
  74. priv->wol_gpio = 0xff;
  75. priv->wol_gap = 20;
  76. priv->ehs_remove_supported = true;
  77. //Устанавливаем частные переменные
  78. //Настраиваем хост для отправки данных на карту
  79. priv->hw_host_to_card = if_sdio_host_to_card;
  80. priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
  81. priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
  82. priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
  83. sdio_claim_host(func);
  84. //Начальное устройство карты
  85. ret = lbs_start_card(priv);
  86. if (lbs_cfg_register(priv))
  87. ret = register_netdev(priv->dev);
  88. err = register_netdevice(dev);
  89. //Особые функции драйвера устройства Wi-Fi
  90. //Работа сетевого устройства неспецифическая функция
  91. static const struct net_device_ops lbs_netdev_ops = {
  92. .ndo_open = lbs_dev_open, //Открыть
  93. .ndo_stop = lbs_eth_stop, //Стоп
  94. .ndo_start_xmit = lbs_hard_start_xmit, //Начинаем отправку данных
  95. .ndo_set_mac_address = lbs_set_mac_address, //Установить mac-адрес
  96. .ndo_tx_timeout = lbs_tx_timeout, // Тайм-аут отправки
  97. .ndo_set_multicast_list = lbs_set_multicast_list, //адрес многоадресной рассылки
  98. .ndo_change_mtu = eth_change_mtu, //Максимальная единица передачи
  99. .ndo_validate_addr = eth_validate_addr, //Определяем достоверность адреса

3. Прием данных решается прерыванием

Основным методом получения данных сетевым оборудованием является запуск функции обработки прерывания устройства. Функция обработки прерывания определяет тип прерывания. Если это прерывание приема, полученные данные считываются и выделяется sk_buffструктура. буфер данных данных, скопируйте полученные данные в буфер данных и вызовите функцию netif_rx() для передачи sk_buff протоколу верхнего уровня.

Найдите if_sdio_interrupt, вы можете знать, что это sdio_claim_irq(func, if_sdio_interrupt) ,func->irq_handler = if_sdio_interrupt. При обработчике прерывания s3cmci_irqфункцияизS3C2410_SDIIMSK_SDIOIRQ При срабатывании прерывания будет вызвана функция if_sdio_interrupt() для получения данных.

[cpp] view plain copy

  1. static void if_sdio_interrupt(struct sdio_func *func)
  2. ret = if_sdio_card_to_host(card); //Данные, полученные от беспроводной сетевой карты, или сообщаемые данные
  3. //Читаем данные по порту и помещаем их в буфер карты
  4. ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
  5. 1. Здесь одна рука обрабатывает прерывания, а 2
  6. switch (type) { //обработка cmd data запрос события
  7. case MVMS_CMD:
  8. ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk – 4); //Обработка запрошенного командного прерывания
  9. if (ret)
  10. goto out;
  11. break;
  12. case MVMS_DAT:
  13. ret = if_sdio_handle_data(card, card->buffer + 4, chunk – 4);//Обработка прерывания данных приложения
  14. if (ret)
  15. goto out;
  16. break;
  17. case MVMS_EVENT:
  18. ret = if_sdio_handle_event(card, card->buffer + 4, chunk – 4);//Прерывание приложения обработки событий
  19. //Процесс чтения пакета
  20. lbs_process_rxed_packet(card->priv, skb);
  21. //Если это прерывание , отправьте пакет skb на уровень протокола, эта функция
  22. //netif_rx(skb), предоставляемый уровнем протокола
  23. if (in_interrupt())
  24. netif_rx(skb); //Отправлено на уровень протокола
  25. 2//Прочитайте данные на порту и поместите их в буфер карты
  26. ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
  27. //Чтение адреса, адреса назначения, количества и т. д.
  28. int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count)
  29. return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
  30. ret = mmc_io_rw_extended(func->card, write,func->num, addr, incr_addr, buf,blocks, func->cur_blksize);
  31. cmd.arg = write ? 0x80000000 : 0x00000000;
  32. //wait for request
  33. mmc_wait_for_req(card->host, &mrq);
  34. Начать отвечать
  35. mmc_start_request(host, mrq);
  36. wait_for_completion(&complete);
  37. host->ops->request(host, mrq);

4、 Отправка данных

[cpp] view plain copy

  1. //Уровень IP передает данные на уровень интерфейса протокола сетевого устройства через dev_queue_xmit(), а уровень сетевого интерфейса регистрирует их через netdevice Функцияиз Отправка данныхфункция
  2. int dev_queue_xmit(struct sk_buff *skb)
  3. if (!netif_tx_queue_stopped(txq)) {
  4. __this_cpu_inc(xmit_recursion);
  5. //Аппаратное обеспечение устройства начинает отправку
  6. rc = dev_hard_start_xmit(skb, dev, txq);
  7. //Операции вызова в сети Wi-Fi
  8. rc = ops->ndo_start_xmit(skb, dev);
  9. dev->netdev_ops = &lbs_netdev_ops; //Функция работы устройства
  10. //Обработка данных прошивки sdio и данных ядра main_thread основного потока
  11. priv->main_thread = kthread_run(lbs_thread, dev, “lbs_main”);
  12. //Вызов хост_to_card Прямо сейчасif_sdio_card_to_hostфункция。
  13. int ret = priv->hw_host_to_card(priv, MVMS_DAT,priv->tx_pending_buf,priv->tx_pending_len);
  14. Почему if_sdio_to_host? ?Потому что этот определен в пробфункции
  15. //Настраиваем хост для отправки данных на карту
  16. priv->hw_host_to_card = if_sdio_host_to_card;
  17. static int if_sdio_host_to_card(struct lbs_private *priv,u8 type, u8 *buf, u16 nb)
  18. //Копируем данные из buf в пакет sdio и обрабатываем пакет sdio
  19. memcpy(packet->buffer + 4, buf, nb);
  20. //Создаем рабочую очередь
  21. queue_work(card->workqueue, &card->packet_worker);
  22. //Инициализируем очередь
  23. INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
  24. //sdio запись данных
  25. ret = sdio_writesb(card->func, card->ioport, packet->buffer, packet->nb);
  26. //порт расширения записи mmc
  27. ret = mmc_io_rw_extended(func->card, write,func->num, addr, incr_addr, buf,blocks, func->cur_blksize);
  28. //wait for request
  29. mmc_wait_for_req(card->host, &mrq);
  30. mrq->done_data = &complete;
  31. mrq->done = mmc_wait_done;
  32. mmc_start_request(host, mrq);
  33. //Завершаем ожидание и завершаем запись данных
  34. wait_for_completion(&complete);
  35. host->ops->request(host, mrq);
  36. //Завершаем и отправляем данные

5、Удалятьфункция

Когда sdio-карта будет удалена, драйвер вызовет эту функцию для завершения соответствующей операции. Например, занятые ресурсы освобождаются, функция func отключается и хост освобождается.

[cpp] view plain copy

  1. if_sdio_remove(struct sdio_func *func)
  2. —->lbs_stop_card(card->priv);
  3. lbs_remove_card(card->priv);
  4. —->kthread_stop(priv->main_thread); //Завершаем поток ядра
  5. lbs_free_adapter(priv);
  6. lbs_cfg_free(priv);
  7. free_netdev(dev);
  8. flush_workqueue(card->workqueue); //Обновляем рабочую очередь
  9. destroy_workqueue(card->workqueue);
  10. sdio_claim_host(func);
  11. sdio_release_irq(func);
  12. sdio_disable_func(func);
  13. sdio_release_host(func);

Заявление об авторских правах: Содержание этой статьи добровольно предоставлено пользователями Интернета, а мнения, выраженные в этой статье, представляют собой только точку зрения автора. Этот сайт предоставляет только услуги по хранению информации, не имеет никаких прав собственности и не принимает на себя соответствующие юридические обязательства. Если вы обнаружите на этом сайте какое-либо подозрительное нарушение авторских прав/незаконный контент, отправьте электронное письмо, чтобы сообщить. После проверки этот сайт будет немедленно удален.

Издатель: Full stack программист и руководитель стека, укажите источник для перепечатки: https://javaforall.cn/186181.html Исходная ссылка: https://javaforall.cn

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose