---
description: 'PC Card'
next: books/arch-handbook/partiii
params:
  path: /books/arch-handbook/pccard/
prev: books/arch-handbook/sound
showBookMenu: 'true'
tags: ["pc card", "overview"]
title: 'Глава 16. PC Card'
weight: 18
---

[[pccard]]
= PC Card
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:sectnumoffset: 16
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/arch-handbook/

ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]

ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]

Эта глава расскажет о механизмах FreeBSD для написания драйвера устройства для PC Card или CardBus устройства. Однако в настоящее время она лишь документирует, как добавить новое устройство к существующему драйверу pccard.

[[pccard-adddev]]
== Добавление устройства

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

[[pccard-overview]]
=== Обзор

PC Cards идентифицируются одним из двух способов, оба основаны на _Card Information Structure_ (CIS), хранящейся на карте. Первый метод — использование числовых идентификаторов производителя и продукта. Второй метод — использование удобочитаемых строк, также содержащихся в CIS. Шина PC Card использует централизованную базу данных и некоторые макросы для упрощения шаблона проектирования, помогающего автору драйвера сопоставлять устройства с его драйвером.

Производители оригинального оборудования (OEM) часто разрабатывают эталонный дизайн для продуктов PC Card, а затем продают этот дизайн другим компаниям для продвижения на рынке. Эти компании дорабатывают дизайн, продвигают продукт для своей целевой аудитории или географического региона и размещают на карте свою собственную торговую марку. Доработки физической карты обычно очень незначительны, если они вообще вносятся. Чтобы усилить свой бренд, такие поставщики указывают название своей компании в читаемых человеком строках в пространстве CIS, но оставляют идентификаторы производителя и продукта без изменений.

Из-за такой практики драйверы FreeBSD обычно полагаются на числовые идентификаторы для распознавания устройств. Использование числовых идентификаторов и централизованной базы данных усложняет добавление ID и поддержку карт в систему. Необходимо тщательно проверять, кто на самом деле произвел карту, особенно когда кажется, что у производителя карты уже может быть другой идентификатор производителя в центральной базе данных. Linksys, D-Link и NetGear — это несколько американских производителей сетевого оборудования, которые часто продают один и тот же дизайн. Эти же дизайны могут продаваться в Японии под такими названиями, как Buffalo и Corega. Часто все эти устройства будут иметь одинаковые идентификаторы производителя и продукта.

Код шины PC Card хранит централизованную базу данных информации о картах, но не о том, какой драйвер с ними связан, в [.filename]#/sys/dev/pccard/pccarddevs#. Он также предоставляет набор макросов, которые позволяют легко создавать простые записи в таблице, используемой драйвером для заявки устройств.

Наконец, некоторые устройства очень низкого уровня вообще не содержат идентификации производителя. Эти устройства должны быть обнаружены путем сопоставления читаемых человеком строк CIS. Хотя было бы хорошо, если бы нам не нужен был этот метод в качестве запасного варианта, он необходим для некоторых очень дешевых CD-плееров и Ethernet-карт. Этот метод, как правило, следует избегать, но ряд устройств перечислен в этом разделе, потому что они были добавлены до осознания OEM-характера бизнеса PC Card. При добавлении новых устройств предпочтительнее использовать числовой метод.

[[pccard-pccarddevs]]
=== Формат файла [.filename]#pccarddevs#

В файле [.filename]#pccarddevs# есть четыре раздела. Первый раздел содержит номера производителей для вендоров, которые их используют. Этот раздел отсортирован в числовом порядке. Следующий раздел включает все продукты, используемые этими вендорами, вместе с их идентификаторами продуктов и строкой описания. Строка описания обычно не используется (вместо этого мы устанавливаем описание устройства на основе читаемого CIS, даже если совпадение найдено по числовому идентификатору). Затем эти два раздела повторяются для устройств, использующих метод строкового сопоставления. Наконец, C-подобные комментарии, заключенные между символами `/*` и `*/`, допускаются в любом месте файла.

Первая часть файла содержит идентификаторы производителей. Пожалуйста, сохраняйте этот список в числовом порядке. Также, пожалуйста, согласовывайте изменения в этом файле, так как мы делимся им с NetBSD для создания общего центра обработки этой информации. Например, вот первые несколько идентификаторов производителей:

[.programlisting]
....
vendor FUJITSU			0x0004  Fujitsu Corporation
vendor NETGEAR_2		0x000b  Netgear
vendor PANASONIC		0x0032	Matsushita Electric Industrial Co.
vendor SANDISK			0x0045	Sandisk Corporation
....

Вероятно, запись `NETGEAR_2` на самом деле относится к OEM-производителю, у которого NETGEAR приобретал карты, и автор поддержки этих карт не знал на тот момент, что Netgear использовал чужой идентификатор. Эти записи довольно просты. Ключевое слово `vendor` обозначает тип строки, за которым следует название производителя. Это название будет повторяться позже в [.filename]#pccarddevs#, а также использоваться в таблицах соответствия драйверов, поэтому оно должно быть коротким и допустимым идентификатором в C. Числовой идентификатор в шестнадцатеричном формате указывает производителя. Не добавляйте идентификаторы вида `0xffffffff` или `0xffff`, так как они зарезервированы (первый означает "идентификатор не установлен", а второй иногда встречается в крайне некачественных картах для указания "отсутствует"). Наконец, следует строковое описание компании, производящей карту. Эта строка в FreeBSD ни для чего не используется, кроме как в комментариях.

Вторая секция файла содержит продукты. Как показано в этом примере, формат аналогичен строкам поставщиков:

[.programlisting]
....
/* Allied Telesis K.K. */
product ALLIEDTELESIS LA_PCM	0x0002 Allied Telesis LA-PCM

/* Archos */
product	ARCHOS ARC_ATAPI	0x0043 MiniCD
....

Ключевое слово `product` следует за именем производителя, повторяющимся сверху. После него идёт название продукта, которое используется драйвером и должно быть допустимым идентификатором в C, но также может начинаться с цифры. Как и в случае с производителями, шестнадцатеричный идентификатор продукта для этой карты следует тем же соглашениям для `0xffffffff` и `0xffff`. Наконец, идёт строковое описание самого устройства. Эта строка обычно не используется в FreeBSD, поскольку драйвер шины pccard в FreeBSD формирует строку из читаемых человеком записей CIS, но она может быть использована в редких случаях, когда этого недостаточно. Продукты перечислены в алфавитном порядке по производителю, затем в числовом порядке по идентификатору продукта. Перед записями каждого производителя есть комментарий в C, а между записями — пустая строка.

Третий раздел аналогичен предыдущему разделу производителей, но все числовые идентификаторы производителей установлены в `-1`, что означает "совпадение с любым найденным" в коде шины pccard FreeBSD. Поскольку это идентификаторы C, их имена должны быть уникальными. В остальном формат идентичен первому разделу файла.

Последний раздел содержит записи для тех карт, которые должны быть идентифицированы по строковым значениям. Формат этого раздела немного отличается от общего раздела:

[.programlisting]
....
product ADDTRON AWP100		{ "Addtron", "AWP-100&spWireless&spPCMCIA", "Version&sp01.02", NULL }
product ALLIEDTELESIS WR211PCM	{ "Allied&spTelesis&spK.K.", "WR211PCM", NULL, NULL } Allied Telesis WR211PCM
....

Знакомое ключевое слово `product` сопровождается названием производителя и именем карты, как и во втором разделе файла. Здесь формат отличается от использованного ранее. Идёт группировка {}, за которой следует несколько строк. Эти строки соответствуют производителю, продукту и дополнительной информации, определённой в кортеже CIS_INFO. Эти строки фильтруются программой, которая генерирует [.filename]#pccarddevs.h#, чтобы заменить &sp на реальный пробел. Строки NULL означают, что соответствующую часть записи следует игнорировать. В приведённом здесь примере есть некорректная запись. Она не должна содержать номер версии, если только он не критичен для работы карты. Иногда у производителей может быть множество различных версий карты в обращении, которые все работают, и в таком случае эта информация только затрудняет использование аналогичной карты с FreeBSD. Иногда это необходимо, когда производитель хочет продавать множество различных компонентов под одним брендом из-за рыночных соображений (доступность, цена и т. д.). Тогда это может быть критично для различения карты в тех редких случаях, когда производитель сохранил ту же пару производитель/продукт. На данный момент использование регулярных выражений для сопоставления недоступно.

[[pccard-probe]]
=== Пример процедуры обнаружения

Чтобы понять, как добавить устройство в список поддерживаемых, необходимо разобраться в процедурах `probe` (обнаружение) и/или `match` (сопоставление), которые есть во многих драйверах. В FreeBSD 5.x это немного сложнее из-за наличия слоя совместимости с OLDCARD. Поскольку различия лишь косметические, здесь будет представлена идеализированная версия.

[.programlisting]
....
static const struct pccard_product wi_pccard_products[] = {
	PCMCIA_CARD(3COM, 3CRWE737A, 0),
	PCMCIA_CARD(BUFFALO, WLI_PCM_S11, 0),
	PCMCIA_CARD(BUFFALO, WLI_CF_S11G, 0),
	PCMCIA_CARD(TDK, LAK_CD011WL, 0),
	{ NULL }
};

static int
wi_pccard_probe(dev)
	device_t	dev;
{
	const struct pccard_product *pp;

	if ((pp = pccard_product_lookup(dev, wi_pccard_products,
	    sizeof(wi_pccard_products[0]), NULL)) != NULL) {
		if (pp->pp_name != NULL)
			device_set_desc(dev, pp->pp_name);
		return (0);
	}
	return (ENXIO);
}
....

Вот простая процедура проверки pccard, которая соответствует нескольким устройствам. Как упоминалось выше, название может отличаться (если это не `foo_pccard_probe()`, то это будет `foo_pccard_match()`). Функция `pccard_product_lookup()` является обобщенной функцией, которая проходит по таблице и возвращает указатель на первую запись, которой соответствует. Некоторые драйверы могут использовать этот механизм для передачи дополнительной информации о некоторых картах остальной части драйвера, поэтому в таблице могут быть вариации. Единственное требование — каждая строка таблицы должна содержать `struct pccard_product` в качестве первого элемента.

Рассматривая таблицу `wi_pccard_products`, можно заметить, что все записи имеют вид `PCMCIA_CARD(_foo_, _bar_, _baz_)`. Часть _foo_ — это идентификатор производителя из [.filename]#pccarddevs#. Часть _bar_ — это идентификатор продукта. _baz_ — ожидаемый номер функции для этой карты. Многие pccard-устройства могут иметь несколько функций, поэтому требуется способ различать функцию 1 и функцию 0. Вы можете встретить `PCMCIA_CARD_D`, который включает описание устройства из [.filename]#pccarddevs#. Также могут встречаться `PCMCIA_CARD2` и `PCMCIA_CARD2_D`, которые используются, когда необходимо сопоставить как строки CIS, так и номера производителей, в вариантах «использовать описание по умолчанию» и «взять описание из pccarddevs».

[[pccard-add]]
=== Собираем все вместе

Для добавления нового устройства необходимо сначала получить идентификационную информацию от устройства. Проще всего это сделать, вставив устройство в слот PC Card или CF и выполнив команду `devinfo -v`. Пример вывода:

[.programlisting]
....
        cbb1 pnpinfo vendor=0x104c device=0xac51 subvendor=0x1265 subdevice=0x0300 class=0x060700 at slot=10 function=1
          cardbus1
          pccard1
            unknown pnpinfo manufacturer=0x026f product=0x030c cisvendor="BUFFALO" cisproduct="WLI2-CF-S11" function_type=6 at function=0
....

`manufacturer` и `product` являются числовыми идентификаторами данного продукта, в то время как `cisvendor` и `cisproduct` представляют собой строки описания продукта из CIS.

Поскольку мы сначала хотим предпочесть числовой вариант, попробуем сначала создать запись на его основе. Приведённая выше карта была слегка изменена для целей данного примера. Производитель — BUFFALO, у которого, как мы видим, уже есть запись:

[.programlisting]
....
vendor BUFFALO			0x026f	BUFFALO (Melco Corporation)
....

Но нет записи для этой конкретной карты. Вместо этого мы видим:

[.programlisting]
....
/* BUFFALO */
product BUFFALO WLI_PCM_S11	0x0305	BUFFALO AirStation 11Mbps WLAN
product BUFFALO LPC_CF_CLT	0x0307	BUFFALO LPC-CF-CLT
product	BUFFALO	LPC3_CLT	0x030a	BUFFALO LPC3-CLT Ethernet Adapter
product BUFFALO WLI_CF_S11G	0x030b	BUFFALO AirStation 11Mbps CF WLAN
....

Чтобы добавить устройство, мы можем просто добавить эту запись в [.filename]#pccarddevs#:

[.programlisting]
....
product BUFFALO WLI2_CF_S11G	0x030c	BUFFALO AirStation ultra 802.11b CF
....

После выполнения этих шагов карту можно добавить в драйвер. Это простая операция добавления одной строки:

[.programlisting]
....
static const struct pccard_product wi_pccard_products[] = {
	PCMCIA_CARD(3COM, 3CRWE737A, 0),
	PCMCIA_CARD(BUFFALO, WLI_PCM_S11, 0),
	PCMCIA_CARD(BUFFALO, WLI_CF_S11G, 0),
+	PCMCIA_CARD(BUFFALO, WLI_CF2_S11G, 0),
	PCMCIA_CARD(TDK, LAK_CD011WL, 0),
	{ NULL }
};
....

Обратите внимание, что я добавил символ '`+`' перед строкой, которую добавил, но это только для выделения строки. Не добавляйте его в реальный драйвер. После добавления строки вы можете пересобрать ядро или модуль и протестировать его. Если устройство распознано и работает, отправьте патч. Если оно не работает, определите, что необходимо для его работы, и отправьте патч. Если устройство не распознаётся вообще, вы где-то ошиблись и следует перепроверить каждый шаг.

Если вы коммиттер исходного кода FreeBSD, и всё работает корректно, то можете закоммитить изменения в дерево. Однако есть несколько небольших нюансов, которые следует учесть. [.filename]#pccarddevs# должен быть закоммичен в дерево первым. Затем [.filename]#pccarddevs.h# необходимо перегенерировать и закоммитить вторым шагом, убедившись, что правильный тег $FreeBSD$ присутствует в последнем файле. В конце закоммитьте добавления в драйвер.

[[pccard-pr]]
=== Отправка кода для нового устройства

Пожалуйста, не отправляйте записи о новых устройствах автору напрямую. Вместо этого оформите их как PR и сообщите автору номер PR для учёта. Это гарантирует, что записи не будут потеряны. При отправке PR нет необходимости включать в патч diff-файлы [.filename]#pccardevs.h#, так как они будут перегенерированы. Однако необходимо включить описание устройства, а также патчи для клиентского драйвера. Если название устройства неизвестно, используйте имя OEM99, и автор скорректирует OEM99 после изучения. Коммиттеры не должны коммитить OEM99, а вместо этого найти наибольший OEM-номер и закоммитить на единицу больше.
