The translation is temporarily closed for contributions due to maintenance, please come back later.

Translation

Then allocate and activate all the necessary resources. BecauseAs normally the port range will be released before returning from probe, it has to be allocated again. We expect that the probe routine had properly set all the resource ranges, as well as saved them in the structure softc. If the probe routine had left some resource allocated then it does not need to be allocated again (which would be considered an error).
(itstool) path: sect1/para
English
Then allocate and activate all the necessary resources. As normally the port range will be released before returning from probe, it has to be allocated again. We expect that the probe routine had properly set all the resource ranges, as well as saved them in the structure softc. If the probe routine had left some resource allocated then it does not need to be allocated again (which would be considered an error).
Context English Chinese (Simplified) (zh_CN) State
Then the probe routine should either discover the ranges of all the resources by reading the device configuration registers or make sure that they were set explicitly by the user. We will consider it with an example of on-board memory. The probe routine should be as non-intrusive as possible, so allocation and check of functionality of the rest of resources (besides the ports) would be better left to the attach routine. 探测例程应当或者通过读取设备配置寄存器来发现所有资源的范围,或者确保由用户显式设置。我们将假定一个带板上内存的例子。探测例程应当尽可能是非插入式的,这样分配和检查其余资源功能性的工作就可以更好地留给连接例程来做。
The memory address may be specified in the kernel configuration file or on some devices it may be pre-configured in non-volatile configuration registers. If both sources are available and different, which one should be used? Probably if the user bothered to set the address explicitly in the kernel configuration file they know what they are doing and this one should take precedence. An example of implementation could be: 内存地址可以在内核配置文件中指定,或者对应某些设备可以在非易失性配置寄存器中预先配置。如果两种做法均可用却不同,那么应当用哪个呢?可能用户厌烦在内核配置文件中明确设置地址,但他们知道自己在干什么,则应当优先使用这个。一个实现的例子可能是这样的:

/* try to find out the config address first */
sc->mem0_p = bus_get_resource_start(dev, SYS_RES_MEMORY, 0 /*rid*/);
if(sc->mem0_p == 0) { /* nope, not specified by user */
sc->mem0_p = xxx_read_mem0_from_device_config(sc);


if(sc->mem0_p == 0)
/* can't get it from device config registers either */
goto bad;
} else {
if(xxx_set_mem0_address_on_device(sc) < 0)
goto bad; /* device does not support that address */
}

/* just like the port, set the memory size,
* for some devices the memory size would not be constant
* but should be read from the device configuration registers instead
* to accommodate different models of devices. Another option would
* be to let the user set the memory size as "msize" configuration
* resource which will be automatically handled by the ISA bus.
*/
if(pnperror) { /* only for non-PnP devices */
sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/);
if(sc->mem0_size == 0) /* not specified by user */
sc->mem0_size = xxx_read_mem0_size_from_device_config(sc);

if(sc->mem0_size == 0) {
/* suppose this is a very old model of device without
* auto-configuration features and the user gave no preference,
* so assume the minimalistic case
* (of course, the real value will vary with the driver)
*/
sc->mem0_size = 8*1024;
}

if(xxx_set_mem0_size_on_device(sc) < 0)
goto bad; /* device does not support that size */

if(bus_set_resource(dev, SYS_RES_MEMORY, /*rid*/0,
sc->mem0_p, sc->mem0_size)<0)
goto bad;
} else {
sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/);
}

/* try to find out the config address first */
sc->mem0_p = bus_get_resource_start(dev, SYS_RES_MEMORY, 0 /*rid*/);
if(sc->mem0_p == 0) { /* nope, not specified by user */
sc->mem0_p = xxx_read_mem0_from_device_config(sc);


if(sc->mem0_p == 0)
/* can't get it from device config registers either */
goto bad;
} else {
if(xxx_set_mem0_address_on_device(sc) < 0)
goto bad; /* device does not support that address */
}

/* just like the port, set the memory size,
* for some devices the memory size would not be constant
* but should be read from the device configuration registers instead
* to accommodate different models of devices. Another option would
* be to let the user set the memory size as "msize" configuration
* resource which will be automatically handled by the ISA bus.
*/
if(pnperror) { /* only for non-PnP devices */
sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/);
if(sc->mem0_size == 0) /* not specified by user */
sc->mem0_size = xxx_read_mem0_size_from_device_config(sc);

if(sc->mem0_size == 0) {
/* suppose this is a very old model of device without
* auto-configuration features and the user gave no preference,
* so assume the minimalistic case
* (of course, the real value will vary with the driver)
*/
sc->mem0_size = 8*1024;
}

if(xxx_set_mem0_size_on_device(sc) < 0)
goto bad; /* device does not support that size */

if(bus_set_resource(dev, SYS_RES_MEMORY, /*rid*/0,
sc->mem0_p, sc->mem0_size)<0)
goto bad;
} else {
sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/);
}
Resources for IRQ and DRQ are easy to check by analogy. 类似, 很容易检查IRQ和DRQ所用的资源。
If all went well then release all the resources and return success. 如果一切进行正常,然后就可以释放所有资源并返回成功。
xxx_free_resources(sc);
return 0;
xxx_free_resources(sc);
return 0;
Finally, handle the troublesome situations. All the resources should be deallocated before returning. We make use of the fact that before the structure softc is passed to us it gets zeroed out, so we can find out if some resource was allocated: then its descriptor is non-zero. 最后,处理棘手情况。所有资源应当在返回前被释放。我们利用这样一个事实:softc结构在传递给我们以前被零化,因此我们能够找出是否分配了某些资源:如果分配则这些资源的描述符非零。
bad:

xxx_free_resources(sc);
if(error)
return error;
else /* exact error is unknown */
return ENXIO;
bad:

xxx_free_resources(sc);
if(error)
return error;
else /* exact error is unknown */
return ENXIO;
That would be all for the probe routine. Freeing of resources is done from multiple places, so it is moved to a function which may look like: 这是完整的探测例程。资源的释放从多个地方完成,因此将它挪到一个函数中,看起来可能像下面的样子:
static void
xxx_free_resources(sc)
struct xxx_softc *sc;
{
/* check every resource and free if not zero */

/* interrupt handler */
if(sc->intr_r) {
bus_teardown_intr(sc->dev, sc->intr_r, sc->intr_cookie);
bus_release_resource(sc->dev, SYS_RES_IRQ, sc->intr_rid,
sc->intr_r);
sc->intr_r = 0;
}

/* all kinds of memory maps we could have allocated */
if(sc->data_p) {
bus_dmamap_unload(sc->data_tag, sc->data_map);
sc->data_p = 0;
}
if(sc->data) { /* sc->data_map may be legitimately equal to 0 */
/* the map will also be freed */
bus_dmamem_free(sc->data_tag, sc->data, sc->data_map);
sc->data = 0;
}
if(sc->data_tag) {
bus_dma_tag_destroy(sc->data_tag);
sc->data_tag = 0;
}

... free other maps and tags if we have them ...

if(sc->parent_tag) {
bus_dma_tag_destroy(sc->parent_tag);
sc->parent_tag = 0;
}

/* release all the bus resources */
if(sc->mem0_r) {
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->mem0_rid,
sc->mem0_r);
sc->mem0_r = 0;
}
...
if(sc->port0_r) {
bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->port0_rid,
sc->port0_r);
sc->port0_r = 0;
}
}
static void
xxx_free_resources(sc)
struct xxx_softc *sc;
{
/* check every resource and free if not zero */

/* interrupt handler */
if(sc->intr_r) {
bus_teardown_intr(sc->dev, sc->intr_r, sc->intr_cookie);
bus_release_resource(sc->dev, SYS_RES_IRQ, sc->intr_rid,
sc->intr_r);
sc->intr_r = 0;
}

/* all kinds of memory maps we could have allocated */
if(sc->data_p) {
bus_dmamap_unload(sc->data_tag, sc->data_map);
sc->data_p = 0;
}
if(sc->data) { /* sc->data_map may be legitimately equal to 0 */
/* the map will also be freed */
bus_dmamem_free(sc->data_tag, sc->data, sc->data_map);
sc->data = 0;
}
if(sc->data_tag) {
bus_dma_tag_destroy(sc->data_tag);
sc->data_tag = 0;
}

... free other maps and tags if we have them ...

if(sc->parent_tag) {
bus_dma_tag_destroy(sc->parent_tag);
sc->parent_tag = 0;
}

/* release all the bus resources */
if(sc->mem0_r) {
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->mem0_rid,
sc->mem0_r);
sc->mem0_r = 0;
}
...
if(sc->port0_r) {
bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->port0_rid,
sc->port0_r);
sc->port0_r = 0;
}
}
xxx_isa_attach xxx_isa_attach
The attach routine actually connects the driver to the system if the probe routine returned success and the system had chosen to attach that driver. If the probe routine returned 0 then the attach routine may expect to receive the device structure softc intact, as it was set by the probe routine. Also if the probe routine returns 0 it may expect that the attach routine for this device shall be called at some point in the future. If the probe routine returns a negative value then the driver may make none of these assumptions. 如果探测例程返回成功并且系统选择连接那个驱动程序,则连接例程负责将驱动程序实际连接到系统。如果探测例程返回0 ,则连接例程期望接收完整的设备结构softc,此结构由探测例程设置。同时,如果探测例程返回0,它可能期望这个设备的连接例程应当在将来的某点被调用。如果探测例程返回负值,则驱动程序可能不会作此假设。
The attach routine returns 0 if it completed successfully or error code otherwise. 如果成功完成,连接例程返回0,否则返回错误码。
The attach routine starts just like the probe routine, with getting some frequently used data into more accessible variables. 连接例程的启动跟探测例程相似,将一些常用数据取到一些更容易访问的变量中。
struct xxx_softc *sc = device_get_softc(dev);
int unit = device_get_unit(dev);
int error = 0;
struct xxx_softc *sc = device_get_softc(dev);
int unit = device_get_unit(dev);
int error = 0;
Then allocate and activate all the necessary resources. As normally the port range will be released before returning from probe, it has to be allocated again. We expect that the probe routine had properly set all the resource ranges, as well as saved them in the structure softc. If the probe routine had left some resource allocated then it does not need to be allocated again (which would be considered an error). 然后分配并激活所需资源。由于端口范围通常在从探测返回前就被释放,因此需要重新分配。我们希望探测例程已经适当地设置了所有的资源范围,并将它们保存在结构softc中。如果探测例程留下了一些被分配的资源,就不需要再次分配(重新分配被视为错误)。
sc->port0_rid = 0;
sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port0_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc->port0_r == NULL)
return ENXIO;

/* on-board memory */
sc->mem0_rid = 0;
sc->mem0_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem0_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc->mem0_r == NULL)
goto bad;

/* get its virtual address */
sc->mem0_v = rman_get_virtual(sc->mem0_r);
sc->port0_rid = 0;
sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port0_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc->port0_r == NULL)
return ENXIO;

/* on-board memory */
sc->mem0_rid = 0;
sc->mem0_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem0_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc->mem0_r == NULL)
goto bad;

/* get its virtual address */
sc->mem0_v = rman_get_virtual(sc->mem0_r);
The DMA request channel (DRQ) is allocated likewise. To initialize it use functions of the <function>isa_dma*()</function> family. For example: DMA请求通道(DRQ)以相似方式被分配。使用<function>isa_dma*()</function>函数族进行初始化。例如:
<function>isa_dmacascade(sc-&gt;drq0);</function> <function>isa_dmacascade(sc-&gt;drq0);</function>
The interrupt request line (IRQ) is a bit special. Besides allocation the driver's interrupt handler should be associated with it. Historically in the old ISA drivers the argument passed by the system to the interrupt handler was the device unit number. But in modern drivers the convention suggests passing the pointer to structure softc. The important reason is that when the structures softc are allocated dynamically then getting the unit number from softc is easy while getting softc from the unit number is difficult. Also this convention makes the drivers for different buses look more uniform and allows them to share the code: each bus gets its own probe, attach, detach and other bus-specific routines while the bulk of the driver code may be shared among them. 中断请求线(IRQ)有点特殊。除了分配以外,驱动程序的中断处理函数也应当与它关联。在古老的ISA驱动程序中,由系统传递给中断处理函数的参量是设备单元号。但在现代驱动程序中,按照约定,建议传递指向结构softc的指针。一个很重要的原因在于当结构softc被动态分配后,从softc取得单元号很容易,而从单元号取得softc很困难。同时,这个约定也使得用于不同总线的应用程序看起来统一,并允许它们共享代码:每个总线有其自己的探测,连接,分离和其他总线相关的例程,而它们之间可以共享大块的驱动程序代码。

sc-&gt;intr_rid = 0;
sc-&gt;intr_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &amp;sc-&gt;intr_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc-&gt;intr_r == NULL)
goto bad;

/*
* XXX_INTR_TYPE is supposed to be defined depending on the type of
* the driver, for example as INTR_TYPE_CAM for a CAM driver
*/
error = bus_setup_intr(dev, sc-&gt;intr_r, XXX_INTR_TYPE,
(driver_intr_t *) xxx_intr, (void *) sc, &amp;sc-&gt;intr_cookie);
if(error)
goto bad;


sc-&gt;intr_rid = 0;
sc-&gt;intr_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &amp;sc-&gt;intr_rid,
/*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE);

if(sc-&gt;intr_r == NULL)
goto bad;

/*
* XXX_INTR_TYPE is supposed to be defined depending on the type of
* the driver, for example as INTR_TYPE_CAM for a CAM driver
*/
error = bus_setup_intr(dev, sc-&gt;intr_r, XXX_INTR_TYPE,
(driver_intr_t *) xxx_intr, (void *) sc, &amp;sc-&gt;intr_cookie);
if(error)
goto bad;

If the device needs to make DMA to the main memory then this memory should be allocated like described before: 如果驱动程序需要与内存进行DMA,则这块内存应当按前述方式分配:
error=bus_dma_tag_create(NULL, /*alignment*/ 4,
/*boundary*/ 0, /*lowaddr*/ BUS_SPACE_MAXADDR_24BIT,
/*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/ NULL, /*filterarg*/ NULL,
/*maxsize*/ BUS_SPACE_MAXSIZE_24BIT,
/*nsegments*/ BUS_SPACE_UNRESTRICTED,
/*maxsegsz*/ BUS_SPACE_MAXSIZE_24BIT, /*flags*/ 0,
&amp;sc-&gt;parent_tag);
if(error)
goto bad;

/* many things get inherited from the parent tag
* sc-&gt;data is supposed to point to the structure with the shared data,
* for example for a ring buffer it could be:
* struct {
* u_short rd_pos;
* u_short wr_pos;
* char bf[XXX_RING_BUFFER_SIZE]
* } *data;
*/
error=bus_dma_tag_create(sc-&gt;parent_tag, 1,
0, BUS_SPACE_MAXADDR, 0, /*filter*/ NULL, /*filterarg*/ NULL,
/*maxsize*/ sizeof(* sc-&gt;data), /*nsegments*/ 1,
/*maxsegsz*/ sizeof(* sc-&gt;data), /*flags*/ 0,
&amp;sc-&gt;data_tag);
if(error)
goto bad;

error = bus_dmamem_alloc(sc-&gt;data_tag, &amp;sc-&gt;data, /* flags*/ 0,
&amp;sc-&gt;data_map);
if(error)
goto bad;

/* xxx_alloc_callback() just saves the physical address at
* the pointer passed as its argument, in this case &amp;sc-&gt;data_p.
* See details in the section on bus memory mapping.
* It can be implemented like:
*
* static void
* xxx_alloc_callback(void *arg, bus_dma_segment_t *seg,
* int nseg, int error)
* {
* *(bus_addr_t *)arg = seg[0].ds_addr;
* }
*/
bus_dmamap_load(sc-&gt;data_tag, sc-&gt;data_map, (void *)sc-&gt;data,
sizeof (* sc-&gt;data), xxx_alloc_callback, (void *) &amp;sc-&gt;data_p,
/*flags*/0);
error=bus_dma_tag_create(NULL, /*alignment*/ 4,
/*boundary*/ 0, /*lowaddr*/ BUS_SPACE_MAXADDR_24BIT,
/*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/ NULL, /*filterarg*/ NULL,
/*maxsize*/ BUS_SPACE_MAXSIZE_24BIT,
/*nsegments*/ BUS_SPACE_UNRESTRICTED,
/*maxsegsz*/ BUS_SPACE_MAXSIZE_24BIT, /*flags*/ 0,
&amp;sc-&gt;parent_tag);
if(error)
goto bad;

/* many things get inherited from the parent tag
* sc-&gt;data is supposed to point to the structure with the shared data,
* for example for a ring buffer it could be:
* struct {
* u_short rd_pos;
* u_short wr_pos;
* char bf[XXX_RING_BUFFER_SIZE]
* } *data;
*/
error=bus_dma_tag_create(sc-&gt;parent_tag, 1,
0, BUS_SPACE_MAXADDR, 0, /*filter*/ NULL, /*filterarg*/ NULL,
/*maxsize*/ sizeof(* sc-&gt;data), /*nsegments*/ 1,
/*maxsegsz*/ sizeof(* sc-&gt;data), /*flags*/ 0,
&amp;sc-&gt;data_tag);
if(error)
goto bad;

error = bus_dmamem_alloc(sc-&gt;data_tag, &amp;sc-&gt;data, /* flags*/ 0,
&amp;sc-&gt;data_map);
if(error)
goto bad;

/* xxx_alloc_callback() just saves the physical address at
* the pointer passed as its argument, in this case &amp;sc-&gt;data_p.
* See details in the section on bus memory mapping.
* It can be implemented like:
*
* static void
* xxx_alloc_callback(void *arg, bus_dma_segment_t *seg,
* int nseg, int error)
* {
* *(bus_addr_t *)arg = seg[0].ds_addr;
* }
*/
bus_dmamap_load(sc-&gt;data_tag, sc-&gt;data_map, (void *)sc-&gt;data,
sizeof (* sc-&gt;data), xxx_alloc_callback, (void *) &amp;sc-&gt;data_p,
/*flags*/0);
After all the necessary resources are allocated the device should be initialized. The initialization may include testing that all the expected features are functional. 分配了所有的资源后,设备应当被初始化。初始化可能包括测试所有特性,确保它们起作用。
if(xxx_initialize(sc) &lt; 0)
goto bad;
if(xxx_initialize(sc) &lt; 0)
goto bad;
The bus subsystem will automatically print on the console the device description set by probe. But if the driver wants to print some extra information about the device it may do so, for example: 总线子系统将自动在控制台上打印由探测例程设置的设备描述。但如果驱动程序想打印一些关于设备的额外信息,也是可能的,例如:

device_printf(dev, "has on-card FIFO buffer of %d bytes\n", sc-&gt;fifosize);

device_printf(dev, "has on-card FIFO buffer of %d bytes\n", sc-&gt;fifosize);
If the initialization routine experiences any problems then printing messages about them before returning error is also recommended. 如果初始化例程遇到任何问题,建议返回错误之前打印有关信息。
The final step of the attach routine is attaching the device to its functional subsystem in the kernel. The exact way to do it depends on the type of the driver: a character device, a block device, a network device, a CAM SCSI bus device and so on. 连接例程的最后一步是将设备连接到内核中的功能子系统。完成这个步骤的精确方式依赖于驱动程序的类型:字符设备、块设备、网络设备、CAM SCSI总线设备等等。
If all went well then return success. 如果所有均工作正常则返回成功。
error = xxx_attach_subsystem(sc);
if(error)
goto bad;

return 0;
error = xxx_attach_subsystem(sc);
if(error)
goto bad;

return 0;

Loading…

Then allocate and activate all the necessary resources. BecauseAs normally the port range will be released before returning from probe, it has to be allocated again. We expect that the probe routine had properly set all the resource ranges, as well as saved them in the structure softc. If the probe routine had left some resource allocated then it does not need to be allocated again (which would be considered an error).
a month ago
Browse all component changes

Glossary

English Chinese (Simplified) (zh_CN)
No related strings found in the glossary.

Source information

Source string comment
(itstool) path: sect1/para
Source string location
book.translate.xml:18682
String age
a month ago
Source string age
a month ago
Translation file
books/zh_CN/arch-handbook.po, string 2026