Feb 28, 2000 onl50t: デスクトップ Solaris 7 cc ドライバのテスト --- cc ドライバのデバッグ#07 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (http://www-online.kek.jp/~inoue/CAMAC/onl50t-sol7/ Desktop/debug-step06.txt) 高エネルギー加速器研究機構 素粒子原子核研究所 物理、オンライングループ 井上 栄二 (1). 現状確認 (A). SPARC CPU-50T、Solaris7 が届いた。 (B). FORCE,CPU-50(UltraSPARC-IIi 300MHz)、に Solaris 7 のシステムを インストールした。 (C). /etc の下のシステム設定の途中、同一SCSIケーブル上に narrow の ディスクと wide のディスクを混在してつないだらシステムが立ち 上がらなくなってしまった。 (D). wide のディスクを narrow のディスクに替えてもらった。 (E). FORCE,CPU-50(UltraSPARC-IIi 300MHz)、に Solaris 7 のシステムを 再インストールした。 (F). /etc の下の各設定、および /export/home の作成をやった。 (G). CPU-50T に Solaris7用の VMEドライバ、FRCvme-2.4.1 をインストール (H). onl50t に ccドライバを make load しようとしたが、64ビット対応に なっていないために組み込めない。 (I). Solaris7、32ビット・カーネルで onl50t を起動して camacドライバを 組み込んだ。 (J). onl50t、Solaris7 で 32ビット・カーネルの下での camacドライバの 動作確認をやった。 正常に実行できた。 (K). Solaris7、32ビット・カーネルの下で、シングルアクション、割り込み を実行した時のデータ転送速度は正常に測定できたが、ブロック転送の データ転送速度を測定時にシステムがフリーズしてしまった。 (L). 32ビットカーネルを使ってブロック転送を実行すると、複数ワードの データ転送時にフリーズすることがある、この時 camacドライバに制御 が移っていないことを確認した。 (M). ドライバプログラムを64ビット対応にするために必要な作業について調 べた。 (N). lintを使ってcamacドライバプログラムをチェック。 camacドライバを    ロード、アンロードできるようになった。 (O). 64ビット・カーネルの下での camacドライバの動作確認をやった。    シングルアクションR/W はNG。 LAM割り込み処理はNG。 ブロック転送は    確認していない。 (P). CGENC、CGENZ、CGENI、CREMIの実行は正常に実行できるようになった。 (Q). camac シングルアクション read/write の部分をデバッグ中にシステムを 壊してしまった。 (R). Solaris 7 のシステム再インストールした(その2)。 (S). /etc の下の各設定、および /export/home の作成をした(その2)。 (T). VMEドライバ、FRCvme-2.4.1 を再インストールした(その2)。 (U). ccドライバをインストールした(その2)。 (V). camac Z、C が正しく動作できるが、camacシングルアクションread/write がうまく実行できない状況に復旧できた。 (2). ここでやるべきこと camac シングルアクション read/write の部分をチェックする。 (3). 現状確認 (3-1). camacシングルアクションread/write を実行時の記録(再掲) onl50t[50]% cam1 Input n a f (data)> <--- ok. cam1プログラムを起動した直後、2917の RUN LEDは一瞬だけ点灯して消える。 正常。 Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)> <--- NG. naf=3,0,0 を実行すると、データウェイ オペレーションは実行され、データウェイ上の インジケータは正しいデータ値を示しているが CPUには正しいデータは返ってこない。 a=0,f=0 は camac側に正しく伝わっている。2917の RUN LEDは点灯したままになる。2917のRESETボタン を押して RUN LEDを消した。 Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)> <--- NG. naf=3,1,0 を実行すると、データウェイ オペレーションは実行され、データウェイ上の インジケータは正しいデータ値を示しているが CPUには正しいデータは返ってこない。 a=1,f=0 は camac側に正しく伝わっている。2917の RUN LEDは点灯したままになる。2917のRESETボタン を押して RUN LEDを消した。 Input n a f (data)>3 0 16 5 N=3 A=0 F=16 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)> <--- NG. naf=3,0,16 を実行すると、データウェイ オペレーションは実行されない。 2917の RUN LEDは点灯したままになる。 2917のRESETボタン を押して RUN LEDを消した。 現在、挿入されているデバッグ用のメッセージを全てコメントアウトして、上と 同じ状況にあることを確認する。 onl50t[53]% cam1 Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>3 0 16 3 N=3 A=0 F=16 Q=0 X=1 Data:000003(Hex) 00000003(Dec) Input n a f (data)>^Conl50t[54]% onl50t[54]% onl50t console login: onl50t console login: Feb 15 15:49:27 onl50t su: 'su root' succeeded for inoue o n /dev/pts/1 Feb 15 15:49:37 onl50t unix: CAMAC device driver V1.4x, 1991-1993 by Y.TAKEUCHI (T.I.T.) 同じ状況であることを確認した。 (4). ddi_put16()、ddi_get16()を使用する (4-1). ddi_put16()のman Kernel Functions for Drivers ddi_put8(9F) NAME ddi_put8, ddi_put16, ddi_put32, ddi_put64, ddi_putb, ddi_putl, ddi_putll, ddi_putw - write data to the mapped memory address, device register or allocated DMA memory address SYNOPSIS #include #include void ddi_put8(ddi_acc_handle_t handle, uint8_t *dev_addr, uint8_t value); void ddi_put16(ddi_acc_handle_t handle, uint16_t *dev_addr, uint16_t value); void ddi_put32(ddi_acc_handle_t handle, uint32_t *dev_addr, uint32_t value); void ddi_put64(ddi_acc_handle_t handle, uint64_t *dev_addr, uint64_t value); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). PARAMETERS handle The data access handle returned from setup calls, such as ddi_regs_map_setup(9F). value The data to be written to the device. dev_addr Base device address. DESCRIPTION These routines generate a write of various sizes to the mapped memory or device register. The ddi_put8(), ddi_put16(), ddi_put32(), and ddi_put64() functions write 8 bits, 16 bits, 32 bits and 64 bits of data, respectively, to the device address, dev_addr. Each individual datum will automatically be translated to maintain a consistent view between the host and the device based on the encoded information in the data access handle. The translation may involve byte-swapping if the host and the device have incompatible endian characteristics. CONTEXT These functions can be called from user, kernel, or inter- rupt context. SEE ALSO SunOS 5.7 Last change: 30 Sep 1996 1 Kernel Functions for Drivers ddi_put8(9F) ddi_get8(9F), ddi_regs_map_free(9F), ddi_regs_map_setup(9F), ddi_rep_get8(9F), ddi_rep_put8(9F), ddi_device_acc_attr(9S) NOTES The functions described in this manual page previously used symbolic names which specified their data access size; the function names have been changed so they now specify a fixed-width data size. See the following table for the new name equivalents: Previous Name New Name ddi_putb ddi_put8 ddi_putw ddi_put16 ddi_putl ddi_put32 ddi_putll ddi_put64 SunOS 5.7 Last change: 30 Sep 1996 2 (4-2). ddi_get16()のman Kernel Functions for Drivers ddi_get8(9F) NAME ddi_get8, ddi_get16, ddi_get32, ddi_get64, ddi_getb, ddi_getw, ddi_getl, ddi_getll - read data from the mapped memory address, device register or allocated DMA memory address SYNOPSIS #include #include uint8_t ddi_get8(ddi_acc_handle_t handle, uint8_t *dev_addr); uint16_t ddi_get16(ddi_acc_handle_t handle, uint16_t *dev_addr); uint32_t ddi_get32(ddi_acc_handle_t handle, uint32_t *dev_addr); uint64_t ddi_get64(ddi_acc_handle_t handle, uint64_t *dev_addr); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). PARAMETERS handle The data access handle returned from setup calls, such as ddi_regs_map_setup(9F). dev_addr Base device address. DESCRIPTION The ddi_get8(), ddi_get16(), ddi_get32(), and ddi_get64() functions read 8 bits, 16 bits, 32 bits and 64 bits of data, respectively, from the device address, dev_addr. Each individual datum will automatically be translated to maintain a consistent view between the host and the device based on the encoded information in the data access handle. The translation may involve byte-swapping if the host and the device have incompatible endian characteristics. RETURN VALUES These functions return the value read from the mapped address. CONTEXT These functions can be called from user, kernel, or inter- rupt context. SEE ALSO SunOS 5.7 Last change: 22 Nov 1996 1 Kernel Functions for Drivers ddi_get8(9F) ddi_put8(9F), ddi_regs_map_free(9F), ddi_regs_map_setup(9F), ddi_rep_get8(9F), ddi_rep_put8(9F) NOTES The functions described in this manual page previously used symbolic names which specified their data access size; the function names have been changed so they now specify a fixed-width data size. See the following table for the new name equivalents: _______________________________________________________________ | Previous Name New Name | | ddi_getb ddi_get8 | | ddi_getw ddi_get16 | | ddi_getl ddi_get32 | | ddi_getll ddi_get64 | |______________________________________________________________| SunOS 5.7 Last change: 22 Nov 1996 2 (4-3). cc64.cファイルの修正 2917のコントロールレジスタ群のハンドルとして kreg_handle を用意し、 データレジスタのハンドルとして data_handleを用意する。 これを使用して ddi_put16()、ddi_get16() を実行する。 (4-3-1). Data Structure部の修正 (A). dev_ops(9S) の man より抜粋。 Data Structures for Drivers dev_ops(9S) NAME dev_ops - device operations structure SYNOPSIS #include #include INTERFACE LEVEL Solaris DDI specific (Solaris DDI). DESCRIPTION dev_ops contains driver common fields and pointers to the bus_ops and cb_ops(9S). Following are the device functions provided in the device operations structure. All fields must be set at compile time. devo_rev Driver build version. Set this to DEVO_REV. devo_refcnt Driver reference count. Set this to 0. devo_getinfo Get device driver information (see getinfo(9E)). devo_identify Determine if a driver is associated with a device. See identify(9E). devo_probe Probe device. See probe(9E). devo_attach Attach driver to dev_info. See attach(9E). devo_detach Detach/prepare driver to unload. See detach(9E). devo_reset Reset device. Not supported in this release.) Set this to nodev. devo_cb_ops Pointer to cb_ops(9S) structure for leaf drivers. devo_bus_ops Pointer to bus operations structure for nexus drivers. Set this to NULL if this is for a leaf driver. devo_power SunOS 5.7 Last change: 24 Jun 1997 1 Data Structures for Drivers dev_ops(9S) Power a device attached to be system. See power(9E). STRUCTURE MEMBERS int devo_rev; int devo_refcnt; int (*devo_getinfo)(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); int (*devo_identify)(dev_info_t *dip); int (*devo_probe)(dev_info_t *dip); int (*devo_attach)(dev_info_t *dip, ddi_attach_cmd_t cmd); int (*devo_detach)(dev_info_t *dip, ddi_detach_cmd_t cmd); int (*devo_reset)(dev_info_t *dip, ddi_reset_cmd_t cmd); struct cb_ops *devo_cb_ops; struct bus_ops *devo_bus_ops; int (*devo_power)(dev_info_t *dip, int component, int level); SEE ALSO attach(9E), detach(9E), getinfo(9E), identify(9E), probe(9E), power(9E), nodev(9F) Writing Device Drivers SunOS 5.7 Last change: 24 Jun 1997 2 (B). power(9E) の man より抜粋。 Driver Entry Points power(9E) NAME power - power a device attached to the system SYNOPSIS #include #include int prefixpower(dev_info_t *dip, int component, int level); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). This entry point is required. If the driver writer does not supply this entry point, the value NULL must be used in the cb-ops(9S) struc- ture instead. PARAMETERS dip A pointer to the device's dev_info structure. component The component of the driver to be managed. level The desired power level for the component. DESCRIPTION The power() function is the device-specific power management entry point. This function is called when the system wants the driver to set the power level of component to level. The level argument is the driver-defined power level to which component is set. Except for power level 0 which is defined by the framework to mean "powered off", the interpretation of level is entirely up to the driver. The component argument is the component of the device to be power-managed. Except for component 0, which must represent the entire device, the interpretation of component is entirely up to the driver. The power() function can assume that the driver will be suspended (using detach(9E) with command DDI_PM_SUSPEND), before a request is made to set component 0 to power level 0 and resumed (using attach(9E) with command DDI_PM_RESUME) after setting component 0 from power level 0 to a non-zero power level. If the system requests an inappropriate power transition for the device (for example, a request to power down a device which has just become busy), then the power level should not be changed and power() should return DDI_FAILURE. RETURN VALUES The power() function returns: SunOS 5.7 Last change: 31 Jan 1997 1 Driver Entry Points power(9E) DDI_SUCCESS Successfully set the power to the requested level. DDI_FAILURE Failed to set the power to the requested level. CONTEXT The power() function is called from user or kernel context only. SEE ALSO attach(9E), cb-ops(9S), detach(9E), nulldev(9F), pm_busy_component(9F), pm_create_components(9F), pm_destroy_components(9F), pm_idle_component(9F) Writing Device Drivers SunOS 5.7 Last change: 31 Jan 1997 2 power のエントリーを用意しない場合には、dev_ops で NULL を使えと指示され ている。 (C). cc64.cファイルを修正する。 onl50t[96]% vi cc64.c : struct cc_device { : ddi_acc_handle_t kreg_handle; /* access handle to csr */ ddi_acc_handle_t datar_handle; /* access handle to data */ struct K_REG *kreg; uint16_t *datar; } ccdevice[NCC]; : struct dev_ops cc_ops = { DEVO_REV, /* devo_rev, */ 0, /* refcnt */ cc_getinfo, /* info */ cc_identify, /* identify */ cc_probe, /* probe */ cc_attach, /* attach */ cc_detach, /* detach */ nodev, /* reset (device reset routine) */ &cc_cb_ops, /* driver operations */ (struct bus_ops *)0, /* bus operations */ NULL /* devo_power */ }; : onl50t[97]% (4-3-2). cc_attach()部の修正 (A). ddi_regs_map_setup の man より抜粋。 Kernel Functions for Drivers ddi_regs_map_setup(9F) NAME ddi_regs_map_setup - set up a mapping for a register address space SYNOPSIS #include #include int ddi_regs_map_setup(dev_info_t *dip, uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handlep); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). PARAMETERS dip Pointer to the device's dev_info structure. rnumber Index number to the register address space set. addrp Pointer to the mapping address base. offset Offset into the register address space. len Length to be mapped. accattrp Pointer to a device access attribute structure of this device (see ddi_device_acc_attr(9S)). handlep Pointer to a data access handle. DESCRIPTION ddi_regs_map_setup() maps in the register set given by rnumber. The register number determines which register set is mapped if more than one exists. offset specifies the starting location within the register space and len indicates the size of the area to be mapped. If len is non-zero, it overrides the length given in the register set description. If both len and offset are 0, the entire space is mapped. The base of the mapped register space is returned in addrp. The device access attributes are specified in the location pointed by the accattrp argument (see ddi_device_acc_attr(9S) for details). The data access handle is returned in handlep. handlep is opaque; drivers should not attempt to interpret its value. The handle is used by the system to encode information for subsequent data access function calls to maintain a con- sistent view between the host and the device. SunOS 5.7 Last change: 1 Jan 1997 1 Kernel Functions for Drivers ddi_regs_map_setup(9F) RETURN VALUES ddi_regs_map_setup() returns: DDI_SUCCESS Successfully set up the mapping for data access. DDI_FAILURE Invalid register number rnumber, offset offset, or length len. DDI_REGS_ACC_CONFLICT Cannot enable the register mapping due to access conflicts with other enabled mappings. CONTEXT ddi_regs_map_setup() must be called from user or kernel con- text. ATTRIBUTES See attributes(5) for descriptions of the following attri- butes: ______________________________________________________________ | ATTRIBUTE TYPE | ATTRIBUTE VALUE | |_____________________________|_______________________________| | Architecture | PCI Local Bus, SBus, ISA, EISA| |_____________________________|_______________________________| SEE ALSO attributes(5), ddi_regs_map_free(9F), ddi_device_acc_attr(9S) Writing Device Drivers SunOS 5.7 Last change: 1 Jan 1997 2 (B). ddi_device_acc_attr の man より抜粋。 Data Structures for Drivers ddi_device_acc_attr(9S) NAME ddi_device_acc_attr - data access attributes structure SYNOPSIS #include #include INTERFACE LEVEL Solaris DDI specific (Solaris DDI). DESCRIPTION The ddi_device_acc_attr structure describes the data access characteristics and requirements of the device. STRUCTURE MEMBERS ushort_t devacc_attr_version; uchar_t devacc_attr_endian_flags; uchar_t devacc_attr_dataorder; The devacc_attr_version member identifies the version number of this structure. The current version number is DDI_DEVICE_ATTR_V0. The devacc_attr_endian_flags member describes the endian characteristics of the device. Specify one of the following values. DDI_NEVERSWAP_ACC Ddata access with no byte swapping. DDI_STRUCTURE_BE_ACC Structural data access in big endian format. DDI_STRUCTURE_LE_ACC Structural data access in little endian format. DDI_STRUCTURE_BE_ACC and DDI_STRUCTURE_LE_ACC describes the endian characteristics of the device as big endian or little endian, respectively. Even though most of the devices will have the same endian characteristics as their buses, there are examples of devices with I/O an processor that has oppo- site endian characteristics of the buses. When DDI_STRUCTURE_BE_ACC or DDI_STRUCTURE_LE_ACC is set, byte swapping will automati- cally be performed by the system if the host machine and the device data formats have opposite endian characteris- tics. The implementation may take advantage of hardware platform byte swapping capabilities. When DDI_NEVERSWAP_ACC is specified, byte swapping will not be invoked in the data access functions. SunOS 5.7 Last change: 27 Oct 1994 1 Data Structures for Drivers ddi_device_acc_attr(9S) The devacc_attr_dataorder member describes order in which the CPU will reference data. Specify one of the following values. DDI_STRICTORDER_ACC The data references must be issued by a CPU in program order. Strict ordering is the default behavior. DDI_UNORDERED_OK_ACC The CPU may re-order the data references. This includes all kinds of re-ordering. For example, . a load followed by a store may be replaced by a store followed by a load. DDI_MERGING_OK_ACC The CPU may merge individual stores to consecu- tive locations. For example, the CPU may turn two consecutive byte stores into one halfword store. It may also batch individual loads. For example, the CPU may turn two con- secutive byte loads into one halfword load. DDI_MERGING_OK_ACC also implies re-ordering. DDI_LOADCACHING_OK_ACC The CPU may cache the data it fetches and reuse it until another store occurs. The default behavior is to fetch new data on every load. DDI_LOADCACHING_OK_ACC also implies merging and re-ordering. DDI_STORECACHING_OK_ACC The CPU may keep the data in the cache and push it to the device (perhaps with other data) at a later time. The default behavior is to push the data right away. DDI_STORECACHING_OK_ACC also implies load caching, merging, and re-ordering. These values are advisory, not mandatory. For example, data can be ordered without being merged or cached, even though a driver requests unordered, merged and cached together. EXAMPLES The following examples illustrate the use of device register address mapping setup functions and different data access functions. Example 1: Using ddi_device_acc_attr() in ddi_regs_map_setup(9F) SunOS 5.7 Last change: 27 Oct 1994 2 Data Structures for Drivers ddi_device_acc_attr(9S) This example demonstrates the use of the ddi_device_acc_attr() structure in ddi_regs_map_setup(9F). It also shows the use of ddi_getw(9F) and ddi_putw(9F) functions in accessing the register contents. dev_info_t *dip; uint_t rnumber; ushort_t *dev_addr; offset_t offset; offset_t len; ushort_t dev_command; ddi_device_acc_attr_t dev_attr; ddi_acc_handle_t handle; ... /* * setup the device attribute structure for little endian, * strict ordering and 16-bit word access. */ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; /* * set up the device registers address mapping */ ddi_regs_map_setup(dip, rnumber, (caddr_t *)&dev_addr, offset, len, &dev_attr, &handle); /* read a 16-bit word command register from the device */ dev_command = ddi_getw(handle, dev_addr); dev_command |= DEV_INTR_ENABLE; /* store a new value back to the device command register */ ddi_putw(handle, dev_addr, dev_command); Example 2: Accessing a Device with Different Apertures The following example illustrates the steps used to access a device with different apertures. We assume that several apertures are grouped under one single "reg" entry. For example, the sample device has four different apertures each 32K in size. The apertures represent YUV little-endian, YUV big-endian, RGB little-endian, and RGB big-endian. This sample device uses entry 1 of the "reg" property list for this purpose. The size of the address space is 128K with each 32K range as a separate aperture. In the register map- ping setup function, the sample driver uses the offset and len parameters to specify one of the apertures. SunOS 5.7 Last change: 27 Oct 1994 3 Data Structures for Drivers ddi_device_acc_attr(9S) ulong_t *dev_addr; ddi_device_acc_attr_t dev_attr; ddi_acc_handle_t handle; uchar_t buf[256]; ... /* * setup the device attribute structure for never swap, * unordered and 32-bit word access. */ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; dev_attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC; /* * map in the RGB big-endian aperture * while running in a big endian machine * - offset 96K and len 32K */ ddi_regs_map_setup(dip, 1, (caddr_t *)&dev_addr, 96*1024, 32*1024, &dev_attr, &handle); /* * Write to the screen buffer * first 1K bytes words, each size 4 bytes */ ddi_rep_putl(handle, buf, dev_addr, 256, DDI_DEV_AUTOINCR); Example 3: Functions Thal Call Out the Data Word Size The following example illustrates the use of the functions that explicitly call out the data word size to override the data size in the device attribute structure. struct device_blk { ushort_t d_command; /* command register */ ushort_t d_status; /* status register */ ulong d_data; /* data register */ } *dev_blkp; dev_info_t *dip; caddr_t dev_addr; ddi_device_acc_attr_t dev_attr; ddi_acc_handle_t handle; uchar_t buf[256]; ... /* * setup the device attribute structure for never swap, * strict ordering and 32-bit word access. */ SunOS 5.7 Last change: 27 Oct 1994 4 Data Structures for Drivers ddi_device_acc_attr(9S) dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; dev_attr.devacc_attr_dataorder= DDI_STRICTORDER_ACC; ddi_regs_map_setup(dip, 1, (caddr_t *)&dev_blkp, 0, 0, &dev_attr, &handle); /* write command to the 16-bit command register */ ddi_putw(handle, &dev_blkp->d_command, START_XFER); /* Read the 16-bit status register */ status = ddi_getw(handle, &dev_blkp->d_status); if (status & DATA_READY) /* Read 1K bytes off the 32-bit data register */ ddi_rep_getl(handle, buf, &dev_blkp->d_data, 256, DDI_DEV_NO_AUTOINCR); SEE ALSO ddi_getw(9F), ddi_putw(9F), ddi_regs_map_setup(9F) Writing Device Drivers SunOS 5.7 Last change: 27 Oct 1994 5 (C). cc64.cファイルを修正 onl50t[105]% vi cc64.c : cc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { /* E.Inoue u_short value; end */ uint16_t value; register struct cc_device *cc; /* register struct cc_device *cc = &ccdevice[0]; */ /* register struct K_REG *k = cc->k; */ int instance; /* E.Inoue */ ddi_device_acc_attr_t dev_acc_attr; /* end */ instance = ddi_get_instance(dip); : /* * the registers look OK, so let's map them in so we can use them */ /* * Initialize the device access attributes for the register * mapping */ dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; /* * Map in the csr register */ if (ddi_regs_map_setup(dip, 1, (caddr_t *)&cc->kreg, 0, 0, &dev_acc_attr, &cc->kreg_handle) != DDI_SUCCESS) { mutex_destroy(&cc->mutex); ddi_remove_intr(cc->dip, 0, cc->iblock_cookie); ddi_soft_state_free(cc_state, instance); return (DDI_FAILURE); } : : /* * reset device (including disabling interrupts) */ ddi_put16(cc->kreg_handle, cc->kreg->csr, CC_RST); : onl50t[115]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[116]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -O -c camlib.c -o camlib.o -I. cc -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -O cam1.c -o cam1 -I. -L. -lcamac f77 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -O cam3.c -o cam3 -I. -L. -lcamac onl50t[117]% onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] drvconfig: Driver (cc) failed to attach Warning: Driver (cc) successfully added to system but failed to attach [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# # onl50t[124]% ls -l /dev/cc lrwxrwxrwx 1 root other 37 Feb 18 15:53 /dev/cc -> /devices/pci@1f ,0/vme@5/cc@2d,ff00:cc onl50t[125]% cam1 Open error: : No such file or directory onl50t[126]% Feb 18 15:52:41 onl50t su: 'su root' succeeded for inoue on /dev/pts/0 Feb 18 15:52:59 onl50t unix: CAMAC device driver V1.4x, 1991-1993 by Y.TAKEUCHI (T.I.T.) onl50t[153]% vi cc64.c : struct cc_device { int status; /* current system status */ : ddi_acc_handle_t kreg_handle; /* access handle to csr */ ddi_acc_handle_t datar_handle; /* access handle to data */ struct K_REG *kreg; uint16_t *datar; } ccdevice[NCC]; : cc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { /* E.Inoue u_short value; end */ uint16_t value; register struct cc_device *cc; /* register struct cc_device *cc = &ccdevice[0]; */ /* register struct K_REG *k = cc->k; */ int instance; /* E.Inoue */ ddi_device_acc_attr_t dev_attr; /* end */ instance = ddi_get_instance(dip); : /* E.Inoue */ /* * the registers look OK, so let's map them in so we can use them */ /* * Initialize the device access attributes for the register * mapping */ dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; /* * Map in the kreg register */ if (ddi_regs_map_setup(dip, 0, (caddr_t *)&cc->kreg, 0, 0, &dev_attr, &cc->kreg_handle) != DDI_SUCCESS) { mutex_destroy(&cc->mutex); ddi_remove_intr(cc->dip, 0, cc->iblock_cookie); ddi_soft_state_free(cc_state, instance); cmn_err(CE_WARN,"cc_attach: can't alloc kreg handle"); return (DDI_FAILURE); } /* * reset device (including disabling interrupts) */ ddi_put16(cc->kreg_handle, &cc->kreg->csr, CC_RST); return (DDI_SUCCESS); } static int cc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { register struct cc_device *cc; /* register struct cc_device *cc = &ccdevice[0]; */ int instance; /* deallocate resources from attach */ instance = ddi_get_instance(dip); cc = ddi_get_soft_state(cc_state,instance); /* E.Inoue */ /* * turn off the device (including interrupts) */ ddi_put16(cc->kreg_handle, &cc->kreg->csr, CC_RST); /* end */ onl50t[149]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[150]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -O -c camlib.c -o camlib.o -I. cc -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -O cam1.c -o cam1 -I. -L. -lcamac f77 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -O cam3.c -o cam3 -I. -L. -lcamac onl50t[151]% su Password: # csh onl50t# source /.cshrc onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# onl50t[152]% cam1 Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>^Conl50t[153]% onl50t[153]% onl50t[164]% vi cc64.c : struct cc_device { : uint16_t dev_kreg; : } ccdevice[NCC]; : cc->k->csr &= (uint16_t)~CC_WRITE; /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)CC_GO; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ /* E.Inoue cc->k->csr |= (uint16_t)CC_GO; /* Go! */ end */ : onl50t[165]% onl50t[171]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[172]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -O -c camlib.c -o camlib.o -I. cc -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -O cam1.c -o cam1 -I. -L. -lcamac f77 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -O cam3.c -o cam3 -I. -L. -lcamac onl50t[173]% onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# : static int camac_s(int unit, u_short mode, u_short naf, u_short *dat) { register struct cc_device *cc; : switch (naf & 0x0018) { case 0x0000: /* CAMAC read */ : /* E.Inoue cc->k->csr &= (uint16_t)~CC_WRITE; end */ /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)~CC_WRITE; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ /* E.Inoue cc->k->csr |= (uint16_t)CC_GO; end */ /* Go! */ /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)CC_GO; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ /* E.Inoue while ((cc->k->csr & ((uint16_t)CC_RDY|(uint16_t)CC_ERR)) == 0 && (uint1 6_t)counter < (uint16_t)CC_TIMEOUT_SINGLE) end */ while (((ddi_get16(cc->kreg_handle, &cc->kreg->csr)) & ((uint16_t)CC_RDY |(uint16_t)CC_ERR)) == 0 && (uint16_t)counter < (uint16_t)CC_TIMEOUT_SINGLE) (uint16_t)counter++; /* E.Inoue if ((cc->k->csr & (uint16_t)CC_RDY) != 0) { end */ if ((ddi_get16(cc->kreg_handle, &cc->kreg->csr) & (uint16_t)CC_RDY) != 0) { if ((mode & (uint16_t)CC_BIT16) == 0) { /* E.Inoue *dat = cc->k->dhr & 0x00FF; *(dat + 1) = cc->k->dlr; end */ *dat = ddi_get16(cc->kreg_handle, &cc->kreg->dhr) & (uint16_t)0x 00FF; *(dat + 1) = ddi_get16(cc->kreg_handle, &cc->kreg->dlr); cmn_err(CE_NOTE," camac_s: read data. --- *dat = 0x%x, *(dat + 1 ) = 0x%x\n", *dat, *(dat + 1)); } else /* E.Inoue *dat = cc->k->dlr; end */ *dat = ddi_get16(cc->kreg_handle, &cc->kreg->dlr); } break; case 0x0010: /* CAMAC write */ : /* E.Inoue cc->k->csr |= (uint16_t)CC_WRITE; end */ /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)CC_WRITE; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ /* E.Inoue cc->k->csr |= (uint16_t)CC_GO; end */ /* Go! */ /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)CC_GO; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ /* E.Inoue while ((cc->k->csr & ((uint16_t)CC_RDY|(uint16_t)CC_ERR)) == 0 && (uint1 6_t)counter < (uint16_t)CC_TIMEOUT_SINGLE) end */ while (((ddi_get16(cc->kreg_handle, &cc->kreg->csr)) & ((uint16_t)CC_RDY |(uint16_t)CC_ERR)) == 0 && (uint16_t)counter < (uint16_t)CC_TIMEOUT_SINGLE) (uint16_t)counter++; /* E.Inoue if ((cc->k->csr & (uint16_t)CC_RDY) != 0) { end */ if ((ddi_get16(cc->kreg_handle, &cc->kreg->csr) & (uint16_t)CC_RDY) != 0 ) { if ((mode & (uint16_t)CC_BIT16) == 0) { /* E.Inoue cc->k->dhr = *dat; cc->k->dlr = *(dat + 1); end */ ddi_put16(cc->kreg_handle, &cc->kreg->dhr, *dat); ddi_put16(cc->kreg_handle, &cc->kreg->dlr, *(dat + 1)); } else { /* E.Inoue cc->k->dlr = *dat; end */ ddi_put16(cc->kreg_handle, &cc->kreg->dlr, *dat); } } break; default: /* NDT */ /* E.Inoue cc->k->csr |= (uint16_t)CC_GO; */ /* Go! */ /* E.Inoue */ cc->dev_kreg = ddi_get16(cc->kreg_handle, &cc->kreg->csr); cc->dev_kreg |= (uint16_t)CC_GO; ddi_put16(cc->kreg_handle, &cc->kreg->csr, cc->dev_kreg); /* end */ break; } /* while ((cc->k->csr & ((uint16_t)CC_DONE | (uint16_t)CC_ERR)) == 0 && (uint16 _t)counter < (uint16_t)CC_TIMEOUT_SINGLE) */ while (((ddi_get16(cc->kreg_handle, &cc->kreg->csr)) & ((uint16_t)CC_DONE | (uint16_t)CC_ERR)) == 0 && (uint16_t)counter < (uint16_t)CC_TIMEOUT_SINGLE) (uint16_t)counter++; /* cc->camac_qx = cc->k->csr; */ cc->camac_qx = ddi_get16(cc->kreg_handle, &cc->kreg->csr); if ((uint16_t)counter >= (uint16_t)CC_TIMEOUT_SINGLE) { cc->status = (uint16_t)CC_STA_SINGLE_TIMEOUT; } return cc->status; } : onl50t[66]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[67]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -O -c camlib.c -o camlib.o -I. cc -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -O cam1.c -o cam1 -I. -L. -lcamac f77 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -O cam3.c -o cam3 -I. -L. -lcamac onl50t[68]% onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# onl50t[69]% cam1 Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>3 0 16 7 N=3 A=0 F=16 Q=0 X=1 Data:000007(Hex) 00000007(Dec) Input n a f (data)>3 0 16 7 N=3 A=0 F=16 Q=0 X=1 Data:000007(Hex) 00000007(Dec) Input n a f (data)>3 0 16 7 N=3 A=0 F=16 Q=0 X=1 Data:000007(Hex) 00000007(Dec) Input n a f (data)>3 0 16 5 N=3 A=0 F=16 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>^Conl50t[70]% onl50t[70]% Feb 22 16:18:43 onl50t unix: CAMAC device driver V1.4x, 1991-1993 by Y.TAKEUCHI (T.I.T.) Feb 22 16:19:30 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x4044 Feb 22 16:19:30 onl50t Feb 22 16:19:30 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 22 16:19:30 onl50t Feb 22 16:19:30 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 22 16:19:30 onl50t Feb 22 16:19:30 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 22 16:19:30 onl50t onl50t console login: onl50t console login: onl50t console login: onl50t console login: Feb 22 16:19:46 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x0 Feb 22 16:19:46 onl50t onl50t console login: onl50t console login: onl50t console login: Feb 22 16:19:59 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x5 Feb 22 16:19:59 onl50t <--- スイッチレジスタを 0x5 にして読み出した onl50t console login: onl50t console login: onl50t console login: Feb 22 16:20:19 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x3 Feb 22 16:20:19 onl50t <--- スイッチレジスタを 0x3 にして読み出した onl50t console login: onl50t console login: onl50t console login: cam1 の起動は正常。 naf=3,0,0 を実行した時 RUN LED は一瞬だけ点灯して すぐに消える。 正常な動作になった。 read を実行した時の読み出しデータは 依然として不正な値になっている。 しかし、上の実行結果からわかるとおり ddi_get16()で読み出した直後のドライバ中の値は正しい値になっている。 ドライバからアプリケーションへ渡す段階で不正な値になってしまっている。 cc_write()ルーチンに出力文を入れて確認する。 onl50t[112]% cam1 Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=0 X=1 Data:000005(Hex) 00000005(Dec) Input n a f (data)>^Conl50t[113]% onl50t[113]% Feb 25 15:27:36 onl50t unix: CAMAC device driver V1.4x, 1991-1993 by Y.TAKEUCHI (T.I.T.) Feb 25 15:28:09 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 15:28:09 onl50t Feb 25 15:28:09 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x44 Feb 25 15:28:09 onl50t onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: Feb 25 15:28:30 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x3 Feb 25 15:28:30 onl50t Feb 25 15:28:30 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 15:28:30 onl50t Feb 25 15:28:30 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x3 Feb 25 15:28:30 onl50t 読み出したデータは camac_s()ルーチンからリターンした時点では正しい値に なっている。 つまり copyout()したデータをアプリケーションが正しく受け取 れていないようだ。 (5). アプリケーションとカーネルの間のデータ受け渡し (5-1). I/O Request Handling (A). User Addresses ユーザスレッドが write(2) システムコールを発行すると、ユーザスペースの バッファのアドレスが渡される: char buffer[] = "python"; count = write(fd, buffer, strlen(buffer) + 1); システムはこの転送を描写するために、iovec(9S) 構造体をアロケートし、 write(2)で渡されるアドレス用に iov_base フィールドをセットして uio(9S) 構造体を作り上げる。 上のケースでは buffer にあたる。 uio(9S)構造体は ドライバのwrite(9E) ルーチンに渡されるものである(uio(9S)構造体についての もっと詳しい情報はVectored I/Oを参照)。 問題はこのアドレスがカーネルスペースではなくてユーザスペースにあり、現在 のメモリー中にあることが保証されないことである。 有効なアドレスである ことさえも保証されない。 デバイスドライバあるいはカーネルからの直接的な ユーザアドレスへのアクセスのどちらの場合にもシステムがクラッシュし得る。 それで、デバイスドライバはユーザアドレスを直にアクセスすべきではない。 その代わりに、カーネルに対するデータ転送を行う Solaris 7 DDI/DKI の中の データ転送ルーチンをいつも使うようにすべきである。 利用できるルーチンの 概要についてはCopying Dataおよびuio 9S Handlingを見よ。 これらのルーチン はページフォルトを処理することが可能である。 適切なユーザページを持って きて透過的にコピーを続けるか、あるいは無効なアクセスが行われた時にエラー を返すかすることによって処理する。 カーネルスペースからユーザスペースにデータをコピーするのにcopyout(9F) が、ユーザスペースからカーネルスペースにデータをコピーするのにcopyin(9F) のルーチンが通常使われる。 ddi_copyout(9F) および ddi_copyin(9F) は 同様に動作するが、これらはioctl(9E) ルーチンで使われる。 copyin(9F) および copyout(9F) はそれぞれのiovec(9S) 構造体で記述されたバッファを 使うことができる。 uiomove(9F) はドライバ(あるいはデバイス)の連続した メモリー領域に全体的な転送を行うことができる。  (B). Vectored I/O キャラクタドライバでは、転送はuio(9S)構造体で記述される。 uio(9S)構造体 は転送の向き、および転送のサイズ、転送の片方(他方はデバイス)のバッファの 並びの情報を収めている。 以下にuio(9S)構造体メンバのリストを示す。 uio(9S)構造体はキャラクタドライバでは重要である。 uio 構造体 uio(9S)構造体は以下のメンバからなる: iovec_t *uio_iov; /* base address of the iovec */ /* buffer description array */ int uio_iovcnt; /* the number of iovec structures */ off_t uio_offset; /* offset into device where data */ /* is transferred from or to */ offset_t uio_loffset /* 64-bit offset into file where */ /* data is transferred from or to */ int uio_resid; /* amount (in bytes) not */ /* transferred on completion */ uio(9S)構造体はドライバのread(9E) およびwrite(9E) エントリポイントに渡さ れる。 この構造体は、gather-write および scatter read が何をコールしたの かサポートするために一般化される。 デバイスに write する時、書かれる べきデータバッファはアプリケーションメモリ上に連続している必要はない。 同様に、デバイスからメモリへの読み出し時、データは連続したストリームで デバイスが送り出すが、アプリケーションメモリ上の非連続領域に送り込むこと ができる。 scatter-gather I/O についてのもっと詳しい情報はreadv(2), writev(2), pread(2) および pwrite(2) を見よ。 それぞれのバッファはiovec(9S) 構造体によって記述される。 この構造体は データ領域に対するポインタと転送されるべきバイト数を収めている。 caddr_t iov_base; /* address of buffer */ int iov_len; /* amount to transfer */ uio構造体はiovec(9S) 構造体のアレーにたいするポインタを収めている。 この アレーのベースアドレスはuio_iovに保存され、エレメントの数はuio_iovcntに ストアされる。 uio_offset フィールドは、アプリケーションが転送を始める必要がある場合に デバイスのなかに32ビットオフセットを収めている。 uio_loffset は64ビット ファイルオフセット用に使われる。 デバイスがオフセットの概念をサポート しないならば、これらのフィールドは支障なく無視される。 ドライバは uio_offset であるのか uio_loffset であるのか(しかし両方ではない)解読すべ きである。 ドライバがドライバ構造体のD_64BIT フラグをセットしたならば、 uio_loffsetを使うべきである。 uio_resid フィールドは複数バイトの転送(uio_iovの全uio_iovフィールドの 合計)として開始し、そしてドライバによってバイト数をセットされなければ ならなず、リターンの前に転送されてはならない。 read(2) および write(2) システムコールはread(9E) および write(9E) エントリポイントからのリターン 値を使う。 これによって、転送が失敗(リターン値が-1)したかどうかを決定 する。 リターン値が成功であることを示している場合、システムコールは、 要求したバイト数からuio_residを引いた数を返す。 uio_resid がドライバで 変更されない場合には、read(2) および write(2)コールは0(end-of-fileを表し ている)を返す、けれどもすべてのデータは転送されている。 uiomove(9F), physio(9F) および aphysio(9F) のサポートルーチンは、uio(9S) 構造体を直接にアップデートする。 アップデートする情報はデータ転送用の アカウントに対するデバイスオフセットである。 シーク可能デバイスを使う 時、位置の概念が関係してくる。 デバイスはuio_offset あるいはuio_loffset の調整が必要なくなる。 この方法でデバイスに対して行われる I/O は、 uio_offset あるいは uio_loffset の可能な最高値で抑制される。 そのような 使い方の例としてはディスクへの raw I/O がある。 位置の概念を持たないデバイスのI/Oを行う時、ドライバはuio_offset あるいは uio_loffset を大切にし、I/O動作を行い、uio_offset あるいは uio_loffset を初期値に戻す。 この方法によるデバイスへのI/Oは、uio_offset あるいは uio_loffset の可能な最高値で抑制されない。 そのような使い方の例としては シリアルラインへのI/O がある。 以下の例はread(9E) 関数でuio_loffsetを保存する一方法を示したものである。 static int xxread(dev_t dev, struct uio *uio_p, cred_t *cred_p) { offset_t off; ... off = uio_p->uio_loffset; /* save the offset */ /* do the transfer */ uio_p->uio_loffset = off; /* restore it */ } (5-2). copyin(),copyout(),writev()について Kernel Functions for Drivers copyin(9F) NAME copyin - copy data from a user program to a driver buffer SYNOPSIS #include #include int copyin(const void *userbuf, void *driverbuf, size_t cn); INTERFACE LEVEL Architecture independent level 1 (DDI/DKI). ARGUMENTS userbuf User program source address from which data is transferred. driverbuf Driver destination address to which data is transferred. cn Number of bytes transferred. DESCRIPTION copyin() copies data from a user program source address to a driver buffer. The driver developer must ensure that ade- quate space is allocated for the destination address. Addresses that are word-aligned are moved most efficiently. However, the driver developer is not obligated to ensure alignment. This function automatically finds the most effi- cient move according to address alignment. RETURN VALUES Under normal conditions a 0 is returned indicating a suc- cessful copy. Otherwise, a -1 is returned if one of the following occurs: o paging fault; the driver tried to access a page of memory for which it did not have read or write access o invalid user address, such as a user area or stack area o invalid address that would have resulted in data being copied into the user block If a -1 is returned to the caller, driver entry point rou- tines should return EFAULT. CONTEXT copyin() can be called from user context only. SunOS 5.6 Last change: 1 May 1996 1 Kernel Functions for Drivers copyin(9F) EXAMPLES A driver ioctl(9E) routine (line 10) can be used to get or set device attributes or registers. In the XX_GETREGS con- dition (line 17), the driver copies the current device register values to a user data area (line 18). If the specified argument contains an invalid address, an error code is returned. 1 struct device { /* layout of physical device registers */ 2 int control; /* physical device control word */ 3 int status; /* physical device status word */ 4 short recv_char; /* receive character from device */ 5 short xmit_char; /* transmit character to device */ 6 }; 7 8 extern struct device xx_addr[]; /* phys. device regs. location */ 9 . . . 10 xx_ioctl(dev_t dev, int cmd, int arg, int mode, 11 cred_t *cred_p, int *rval_p) 12 ... 13 { 14 register struct device *rp = &xx_addr[getminor(dev) >> 4]; 15 switch (cmd) { 16 17 case XX_SETREGS: /* copy device regs. to user program */ 18 if (copyin(arg, rp, sizeof(struct device))) 19 return(EFAULT); 20 break; 21 ... 22 }) 23 ... 24 } SEE ALSO ioctl(9E), bcopy(9F), copyout(9F), ddi_copyin(9F), ddi_copyout(9F), uiomove(9F). Writing Device Drivers NOTES Driver writers who intend to support layered ioctls in their ioctl(9E) routines should use ddi_copyin(9F) instead. Driver defined locks should not be held across calls to this function. SunOS 5.6 Last change: 1 May 1996 2 onlsun1[42]% Kernel Functions for Drivers copyout(9F) NAME copyout - copy data from a driver to a user program SYNOPSIS #include #include int copyout(const void *driverbuf, void *userbuf, size_t cn); INTERFACE LEVEL Architecture independent level 1 (DDI/DKI). PARAMETERS driverbuf Source address in the driver from which the data is transferred. userbuf Destination address in the user program to which the data is transferred. cn Number of bytes moved. DESCRIPTION copyout() copies data from driver buffers to user data space. Addresses that are word-aligned are moved most efficiently. However, the driver developer is not obligated to ensure alignment. This function automatically finds the most effi- cient move algorithm according to address alignment. RETURN VALUES Under normal conditions a 0 is returned to indicate a suc- cessful copy. Otherwise, a -1 is returned if one of the following occurs: o paging fault; the driver tried to access a page of memory for which it did not have read or write access o invalid user address, such as a user area or stack area o invalid address that would have resulted in data being copied into the user block If a -1 is returned to the caller, driver entry point rou- tines should return EFAULT. CONTEXT copyout() can be called from user context only. SunOS 5.7 Last change: 1 May 1996 1 Kernel Functions for Drivers copyout(9F) EXAMPLES Example 1: An ioctl() Routine A driver ioctl(9E) routine (line 10) can be used to get or set device attributes or registers. In the XX_GETREGS con- dition (line 17), the driver copies the current device register values to a user data area (line 18). If the specified argument contains an invalid address, an error code is returned. 1 struct device { /* layout of physical device registers */ 2 int control; /* physical device control word */ 3 int status; /* physical device status word */ 4 short recv_char; /* receive character from device */ 5 short xmit_char; /* transmit character to device */ 6 }; 7 8 extern struct device xx_addr[]; /* phys. device regs. location */ 9 . . . 10 xx_ioctl(dev_t dev, int cmd, int arg, int mode, 11 cred_t *cred_p, int *rval_p) 12 ... 13 { 14 register struct device *rp = &xx_addr[getminor(dev) >> 4]; 15 switch (cmd) { 16 17 case XX_GETREGS: /* copy device regs. to user program */ 18 if (copyout(rp, arg, sizeof(struct device))) 19 return(EFAULT); 20 break; 21 ... 22 } 23 ... 24 } SEE ALSO ioctl(9E), bcopy(9F), copyin(9F), ddi_copyin(9F), ddi_copyout(9F), uiomove(9F) Writing Device Drivers NOTES Driver writers who intend to support layered ioctls in their ioctl(9E) routines should use ddi_copyout(9F) instead. Driver defined locks should not be held across calls to this function. This should not be used from a streams driver. See M_COPYIN and M_COPYOUT in STREAMS Programming Guide. SunOS 5.7 Last change: 1 May 1996 2 onl50t[6]% System Calls write(2) NAME write, pwrite, writev - write on a file SYNOPSIS #include ssize_t write(int fildes, const void *buf, size_t nbyte); ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset); #include ssize_t writev(int fildes, const struct iovec *iov, int iovcnt); DESCRIPTION The write() function attempts to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes. If nbyte is 0, write() will return 0 and have no other results if the file is a regular file; otherwise, the results are unspecified. On a regular file or other file capable of seeking, the actual writing of data proceeds from the position in the file indicated by the file offset associated with fildes. Before successful return from write(), the file offset is incremented by the number of bytes actually written. On a regular file, if this incremented file offset is greater than the length of the file, the length of the file will be set to this file offset. If the O_SYNC flag of the file status flags is set and fildes refers to a regular file, a successful write() does not return until the data is delivered to the underlying hardware. If fildes refers to a socket, write() is equivalent to send(3N) with no flags set. On a file not capable of seeking, writing always takes place starting at the current position. The value of a file offset associated with such a device is undefined. If the O_APPEND flag of the file status flags is set, the file offset will be set to the end of the file prior to each write and no intervening file modification operation will occur between changing the file offset and the write opera- tion. SunOS 5.7 Last change: 28 Jan 1998 1 System Calls write(2) For regular files, no data transfer will occur past the offset maximum established in the open file description with fildes. A write() to a regular file is blocked if mandatory file/record locking is set (see chmod(2)), and there is a record lock owned by another process on the segment of the file to be written: o If O_NDELAY or O_NONBLOCK is set, write() returns -1 and sets errno to EAGAIN. o If O_NDELAY and O_NONBLOCK are clear, write() sleeps until all blocking locks are removed or the write() is terminated by a signal. If a write() requests that more bytes be written than there is room for-for example, if the write would exceed the pro- cess file size limit (see getrlimit(2) and ulimit(2)), the system file size limit, or the free space on the device-only as many bytes as there is room for will be written. For example, suppose there is space for 20 bytes more in a file before reaching a limit. A write() of 512-bytes returns 20. The next write() of a non-zero number of bytes gives a failure return (except as noted for pipes and FIFO below). If write() is interrupted by a signal before it writes any data, it will return -1 with errno set to EINTR. If write() is interrupted by a signal after it successfully writes some data, it will return the number of bytes writ- ten. If the value of nbyte is greater than SSIZE_MAX, the result is implementation-dependent. After a write() to a regular file has successfully returned: o Any successful read(2) from each byte position in the file that was modified by that write will return the data specified by the write() for that position until such byte positions are again modified. o Any subsequent successful write() to the same byte position in the file will overwrite that file data. Write requests to a pipe or FIFO are handled the same as a regular file with the following exceptions: o There is no file offset associated with a pipe, hence each write request appends to the end of the pipe. SunOS 5.7 Last change: 28 Jan 1998 2 System Calls write(2) o Write requests of {PIPE_BUF} bytes or less are guaranteed not to be interleaved with data from other processes doing writes on the same pipe. Writes of greater than {PIPE_BUF} bytes may have data inter- leaved, on arbitrary boundaries, with writes by other processes, whether or not the O_NONBLOCK or O_NDELAY flags are set. o If O_NONBLOCK and O_NDELAY are clear, a write request may cause the process to block, but on normal comple- tion it returns nbyte. o If O_NONBLOCK and O_NDELAY are set, write() does not block the process. If a write() request for PIPE_BUF or fewer bytes succeeds completely write() returns nbyte. Otherwise, if O_NONBLOCK is set, it returns -1 and sets errno to EAGAIN or if O_NDELAY is set, it returns 0. A write() request for greater than {PIPE_BUF} bytes transfers what it can and returns the number of bytes written or it transfers no data and, if O_NONBLOCK is set, returns -1 with errno set to EAGAIN or if O_NDELAY is set, it returns 0. Finally, if a request is greater than PIPE_BUF bytes and all data previously written to the pipe has been read, write() transfers at least PIPE_BUF bytes. When attempting to write to a file descriptor (other than a pipe, a FIFO, a socket, or a STREAM) that supports nonblock- ing writes and cannot accept the data immediately: o If O_NONBLOCK and O_NDELAY are clear, write() blocks until the data can be accepted. o If O_NONBLOCK or O_NDELAY is set, write() does not block the process. If some data can be written without blocking the process, write() writes what it can and returns the number of bytes written. Otherwise, if O_NONBLOCK is set, it returns -1 and sets errno to EAGAIN or if O_NDELAY is set, it returns 0. Upon successful completion, where nbyte is greater than 0, write() will mark for update the st_ctime and st_mtime fields of the file, and if the file is a regular file, the S_ISUID and S_ISGID bits of the file mode may be cleared. For STREAMS files (see intro(2) and streamio(7I)), the operation of write() is determined by the values of the minimum and maximum nbyte range ("packet size") accepted by the STREAM. These values are contained in the topmost STREAM module, and can not be set or tested from user level. If nbyte falls within the packet size range, nbyte bytes are written. If nbyte does not fall within the range and the SunOS 5.7 Last change: 28 Jan 1998 3 System Calls write(2) minimum packet size value is zero, write() breaks the buffer into maximum packet size segments prior to sending the data downstream (the last segment may be smaller than the maximum packet size). If nbyte does not fall within the range and the minimum value is non-zero, write() fails and sets errno to ERANGE. Writing a zero-length buffer (nbyte is zero) to a STREAMS device sends a zero length message with zero returned. However, writing a zero-length buffer to a pipe or FIFO sends no message and zero is returned. The user program may issue the I_SWROPT ioctl(2) to enable zero-length messages to be sent across the pipe or FIFO (see streamio(7I)). When writing to a STREAM, data messages are created with a priority band of zero. When writing to a socket or to a STREAM that is not a pipe or a FIFO: o If O_NDELAY and O_NONBLOCK are not set, and the STREAM cannot accept data (the STREAM write queue is full due to internal flow control conditions), write() blocks until data can be accepted. o If O_NDELAY or O_NONBLOCK is set and the STREAM cannot accept data, write() returns -1 and sets errno to EAGAIN. o If O_NDELAY or O_NONBLOCK is set and part of the buffer has already been written when a condition occurs in which the STREAM cannot accept additional data, write() terminates and returns the number of bytes written. The write() and writev() functions will fail if the STREAM head had processed an asynchronous error before the call. In this case, the value of errno does not reflect the result of write() or writev() but reflects the prior error. pwrite() The pwrite() function performs the same action as write(), except that it writes into a given position without changing the file pointer. The first three arguments to pwrite() are the same as write() with the addition of a fourth argument offset for the desired position inside the file. writev() The writev() function performs the same action as write(), but gathers the output data from the iovcnt buffers speci- fied by the members of the iov array: iov[0], iov[1], ..., iov[iovcnt-1]. The iovcnt buffer is valid if greater than 0 and less than or equal to {IOV_MAX}. See intro(2) for a definition of {IOV_MAX}. SunOS 5.7 Last change: 28 Jan 1998 4 System Calls write(2) The iovec structure contains the following members: caddr_t iov_base; int iov_len; Each iovec entry specifies the base address and length of an area in memory from which data should be written. The wri- tev() function always writes all data from an area before proceeding to the next. If fildes refers to a regular file and all of the iov_len members in the array pointed to by iov are 0, writev() will return 0 and have no other effect. For other file types, the behavior is unspecified. If the sum of the iov_len values is greater than SSIZE_MAX, the operation fails and no data is transferred. RETURN VALUES Upon successful completion, write() returns the number of bytes actually written to the file associated with fildes. This number is never greater than nbyte. Otherwise, -1 is returned, the file-pointer remains unchanged, and errno is set to indicate the error. Upon successful completion, writev() returns the number of bytes actually written. Otherwise, it returns -1, the file-pointer remains unchanged, and errno is set to indicate an error. ERRORS The write(), pwrite(), and writev() functions will fail if: EAGAIN Mandatory file/record locking is set, O_NDELAY or O_NONBLOCK is set, and there is a blocking record lock; total amount of system memory available when reading using raw I/O is temporarily insuffi- cient; an attempt is made to write to a STREAM that can not accept data with the O_NDELAY or O_NONBLOCK flag set; or a write to a pipe or FIFO of PIPE_BUF bytes or less is requested and less than nbytes of free space is available. EBADF The fildes argument is not a valid file descriptor open for writing. EDEADLK The write was going to go to sleep and cause a deadlock situation to occur. EDQUOT The user's quota of disk blocks on the file system containing the file has been exhausted. SunOS 5.7 Last change: 28 Jan 1998 5 System Calls write(2) EFAULT The buf argument points to an illegal address. EFBIG An attempt is made to write a file that exceeds the process's file size limit or the maximum file size (see getrlimit(2) and ulimit(2)). EFBIG The file is a regular file, nbyte is greater than 0, and the starting position is greater than or equal to the offset maximum established in the file description associated with fildes. EINTR A signal was caught during the write operation and no data was transferred. EIO The process is in the background and is attempting to write to its controlling terminal whose TOSTOP flag is set, or the process is neither ignoring nor blocking SIGTTOU signals and the process group of the process is orphaned. ENOLCK Enforced record locking was enabled and {LOCK_MAX} regions are already locked in the system, or the system record lock table was full and the write could not go to sleep until the blocking record lock was removed. ENOLINK The fildes argument is on a remote machine and the link to that machine is no longer active. ENOSPC During a write to an ordinary file, there is no free space left on the device. ENOSR An attempt is made to write to a STREAMS with insufficient STREAMS memory resources available in the system. ENXIO A hangup occurred on the STREAM being written to. EPIPE An attempt is made to write to a pipe or a FIFO that is not open for reading by any process, or that has only one end open (or to a file descrip- tor created by socket(3N), using type SOCK_STREAM that is no longer connected to a peer endpoint). A SIGPIPE signal will also be sent to the process. The process dies unless special provisions were taken to catch or ignore the signal. ERANGE The transfer request size was outside the range supported by the STREAMS file associated with fildes. SunOS 5.7 Last change: 28 Jan 1998 6 System Calls write(2) The pwrite() function fails and the file pointer remains unchanged if: ESPIPE The fildes argument is associated with a pipe or FIFO. The writev() function will fail if: EINVAL The sum of the iov_len values in the iov array would overflow an ssize_t. The write() and writev() functions may fail if: EINVAL The STREAM or multiplexer referenced by fildes is linked (directly or indirectly) downstream from a multiplexer. ENXIO A request was made of a non-existent device, or the request was outside the capabilities of the device. ENXIO A hangup occurred on the STREAM being written to. A write to a STREAMS file may fail if an error message has been received at the STREAM head. In this case, errno is set to the value included in the error message. The writev() function may fail if: EINVAL The iovcnt argument was less than or equal to 0 or greater than {IOV_MAX}; one of the iov_len values in the iov array was negative; or the sum of the iov_len values in the iov array overflowed an int. USAGE The pwrite() function has a transitional interface for 64- bit file offsets. See lf64(5). ATTRIBUTES See attributes(5) for descriptions of the following attri- butes: ____________________________________________________________ | ATTRIBUTE TYPE | ATTRIBUTE VALUE | |_____________________________|_____________________________| | MT-Level | write() is Async-Signal-Safe| |_____________________________|_____________________________| SEE ALSO Intro(2), chmod(2), creat(2), dup(2), fcntl(2), getrlimit(2), ioctl(2), lseek(2), open(2), pipe(2), ulimit(2), send(3N), socket(3N), attributes(5), lf64(5), streamio(7I) SunOS 5.7 Last change: 28 Jan 1998 7 onl50t[8]% (5-3). uio.h について onl50t[23]% cat /usr/include/sys/uio.h /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* * Copyright (c) 1996, by Sun Microsystems, Inc. * All rights reserved. */ #ifndef _SYS_UIO_H #define _SYS_UIO_H #pragma ident "@(#)uio.h 1.29 97/06/29 SMI" /* SVr4.0 1.6 */ #include #ifdef __cplusplus extern "C" { #endif #include /* * I/O parameter information. A uio structure describes the I/O which * is to be performed by an operation. Typically the data movement will * be performed by a routine such as uiomove(), which updates the uio * structure to reflect what was done. */ #if defined(_XPG4_2) typedef struct iovec { void *iov_base; size_t iov_len; } iovec_t; #else typedef struct iovec { caddr_t iov_base; #if defined(_LP64) size_t iov_len; #else long iov_len; #endif } iovec_t; #endif /* defined(_XPG4_2) */ #if defined(_SYSCALL32) /* Kernel's view of user ILP32 iovec struct */ typedef struct iovec32 { caddr32_t iov_base; int32_t iov_len; } iovec32_t; #endif /* _SYSCALL32 */ #if !defined(_XPG4_2) || defined(__EXTENSIONS__) /* * Segment flag values. */ typedef enum uio_seg { UIO_USERSPACE, UIO_SYSSPACE, UIO_USERISPACE } uio_seg_t; typedef struct uio { iovec_t *uio_iov; /* pointer to array of iovecs */ int uio_iovcnt; /* number of iovecs */ lloff_t _uio_offset; /* file offset */ uio_seg_t uio_segflg; /* address space (kernel or user) */ short uio_fmode; /* file mode flags */ lldaddr_t _uio_limit; /* u-limit (maximum "block" offset) */ ssize_t uio_resid; /* residual count */ } uio_t; #define uio_loffset _uio_offset._f #if !defined(_LP64) #define uio_offset _uio_offset._p._l #else #define uio_offset uio_loffset #endif #define uio_llimit _uio_limit._f #if !defined(_LP64) #define uio_limit _uio_limit._p._l #else #define uio_limit uio_llimit #endif /* * I/O direction. */ typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t; #endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */ #if defined(_KERNEL) int uiomove(void *, size_t, enum uio_rw, uio_t *); int ureadc(int, uio_t *); /* should be errno_t in future */ int uwritec(struct uio *); int uiomvuio(uio_t *, uio_t *); void uioskip(uio_t *, size_t); int uiodup(uio_t *, uio_t *, iovec_t *, int); int uioipcopyin(void *, size_t, uio_t *, unsigned short *, int, int); int uioipcopyout(void *, size_t, uio_t *, unsigned short *, int, int); int uiopageflip(void *, size_t, uio_t *); #else /* defined(_KERNEL) */ #if defined(__STDC__) extern ssize_t readv(int, const struct iovec *, int); extern ssize_t writev(int, const struct iovec *, int); #else /* defined(__STDC__) */ extern ssize_t readv(); extern ssize_t writev(); #endif /* defined(__STDC__) */ #endif /* defined(_KERNEL) */ #ifdef __cplusplus } #endif #endif /* _SYS_UIO_H */ onl50t[24]% iovec構造体は64ビット用のものになっている。 32ビットアーキテクチャで 使っていたiovec構造体に相当するものは、iovec32構造体として用意されて いる。 iovec構造体を使っている個所をiovec32構造体を使うように修正して みるかな。 その前にcamacライブラリおよびcamac例題プログラムをv9アーキテ クチャ用にコンパイルするように-xarch=v9オプションを指定してコンパイル し直してみる。 (5-4). cc64.cファイルの修正 : static int cc_write(dev_t dev, struct uio *uio, cred_t *cred_p) { /* register struct cc_device *cc = &ccdevice[0]; */ register struct cc_device *cc; /* E.Inoue */ register struct iovec *iov = uio->uio_iov; /* end */ /* register struct iovec32 *iov = uio->uio_iov; */ register u_short mode, naf; register int len, code, step_count; struct uio uio_save, *uios = &uio_save; /* E.Inoue */ struct iovec iov_save, *iovs = &iov_save; /* end */ /* struct iovec32 iov_save, *iovs = &iov_save; */ int retlen; char klname[9]; minor_t unit; unit = getminor(dev); cc = ddi_get_soft_state(cc_state,unit); : onl50t[174]% vi Makefile : camlib.o: camlib.h camlib.c # $(CC) $(CFLAGS) -c camlib.c -o $@ -I. $(CC) -xarch=v9 $(CFLAGS) -c camlib.c -o $@ -I. forlib.o: camlib.h forlib.c # $(CC) $(CFLAGS) -c forlib.c -o $@ -I. $(CC) -xarch=v9 $(CFLAGS) -c forlib.c -o $@ -I. ########## for examples ########## cam1 : cam1.c # $(CC) $(CFLAGS) cam1.c -o cam1 $(CLIB) $(CC) -xarch=v9 $(CFLAGS) cam1.c -o cam1 $(CLIB) cam2 : cam2.f # $(FC) $(FFLAGS) cam2.f -o cam2 $(CLIB) $(FC) -xarch=v9 $(FFLAGS) cam2.f -o cam2 $(CLIB) cam3 : cam3.c # $(CC) $(CFLAGS) cam3.c -o cam3 $(CLIB) $(CC) -xarch=v9 $(CFLAGS) cam3.c -o cam3 $(CLIB) : onl50t[175]% onl50t[177]% pwd /export/home/onl50t/inoue/CAMAC/FORCE-50T-sol7/script onl50t[178]% vi cc_build.sh #!/sbin/sh # # cc_build.sh 15-OCt-1993 Y.Takeuchi(T.I.T.) # modified 14-Feb-2000 E.Inoue(KEK) # ARCH=`uname -m` echo '[Building for' $ARCH']' cc -c -D_KERNEL -D_MACHDEP -DSUNDDI -DKERNEL -D$ARCH \ -I. -I/usr/include -I/usr/share/src/uts/$ARCH cc.c ld -r -o cc cc.o # #cc -c -D_SYSCALL32 -D_KERNEL -xarch=v9 -D_MACHDEP -DSUNDDI -DKERNEL -D$ARCH \ cc -c -D_KERNEL -xarch=v9 -D_MACHDEP -DSUNDDI -DKERNEL -D$ARCH \ -I. -I/usr/include -I/usr/share/src/uts/$ARCH \ -xcode=abs32 -xregs=no%appl -xO3 -c cc64.c ld -r -o cc64 cc64.o onl50t[179]% onl50t[186]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[187]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -xarch=v9 -O -c camlib.c -o camlib.o -I. cc -xarch=v9 -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -xarch=v9 -O cam1.c -o cam1 -I. -L. -lcamac f77 -xarch=v9 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -xarch=v9 -O cam3.c -o cam3 -I. -L. -lcamac onl50t[188]% onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# onl50t[190]% cam1 Input n a f (data)>3 1 0 N=3 A=1 F=0 Q=1 X=1 Data:000003(Hex) 00000003(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000000(Hex) 00000000(Dec) Input n a f (data)>3 0 16 7 N=3 A=0 F=16 Q=1 X=1 Data:000007(Hex) 00000007(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000007(Hex) 00000007(Dec) Input n a f (data)>^Conl50t[191]% onl50t[191]% onl50t console login: Feb 25 16:54:31 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x4000 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x4000 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x44 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:54:31 onl50t Feb 25 16:54:31 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x44 Feb 25 16:54:31 onl50t onl50t console login: onl50t console login: onl50t console login: onl50t console login: Feb 25 16:55:07 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x3 Feb 25 16:55:07 onl50t Feb 25 16:55:07 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:55:07 onl50t Feb 25 16:55:07 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x3 Feb 25 16:55:07 onl50t onl50t console login: onl50t console login: onl50t console login: onl50t console login: Feb 25 16:55:21 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x0 Feb 25 16:55:21 onl50t Feb 25 16:55:21 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:55:21 onl50t Feb 25 16:55:21 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x0 Feb 25 16:55:21 onl50t onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: onl50t console login: Feb 25 16:55:52 onl50t unix: NOTICE: camac_s: read data. --- *dat = 0x0, *(dat + 1) = 0x7 Feb 25 16:55:52 onl50t Feb 25 16:55:52 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 0] = 0x0 Feb 25 16:55:52 onl50t Feb 25 16:55:52 onl50t unix: NOTICE: cc_write: debug step04. --- cc->data_area[ 1] = 0x7 Feb 25 16:55:52 onl50t ok. camacシングルアクションread/write はデータ転送も含めて正常に実行でき た。 デバッグ用の文をはずして再度動作を確認する。 onl50t[202]% make clean \rm -f cc cc64 *.o libcamac.a cam1 cam2 cam3 *~ core onl50t[203]% make ./script/cc_build.sh [Building for sun4u] rm -f cc.o cc -xarch=v9 -O -c camlib.c -o camlib.o -I. cc -xarch=v9 -O -c forlib.c -o forlib.o -I. rm -f libcamac.a ar rcv libcamac.a camlib.o forlib.o a - camlib.o a - forlib.o ar: writing libcamac.a cc -xarch=v9 -O cam1.c -o cam1 -I. -L. -lcamac f77 -xarch=v9 -fast -O3 -u cam2.f -o cam2 -I. -L. -lcamac cam2.f: MAIN: cc -xarch=v9 -O cam3.c -o cam3 -I. -L. -lcamac onl50t[204]% onl50t# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl50t# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] [Configuring CAMAC device driver] [Making CAMAC device files] sun4u onl50t# onl50t[205]% cam1 Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000000(Hex) 00000000(Dec) Input n a f (data)>3 0 16 777 N=3 A=0 F=16 Q=1 X=1 Data:000309(Hex) 00000777(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000309(Hex) 00000777(Dec) Input n a f (data)>3 0 16 5555 N=3 A=0 F=16 Q=1 X=1 Data:0015B3(Hex) 00005555(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:0015B3(Hex) 00005555(Dec) Input n a f (data)>^Conl50t[206]% onl50t[206]% onl50t console login: onl50t console login: onl50t console login: Feb 28 16:20:10 onl50t unix: CAMAC device driver V1.4x, 19 91-1993 by Y.TAKEUCHI (T.I.T.) ok. 正常に動作している。 続いて、割り込み処理の部分をデバッグする。 ---xxxx ここまでやった(継続中) --- (6). セクション (6-1). サブセクション (6-1-1). サブサブセクション