QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3287|回复: 0
打印 上一主题 下一主题

Port I/O from BCB apps

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2005-1-26 12:58 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>. b1 P1 P; B8 c% d  \
You can't. Well sort of, you can't do port I/O from a BCB apps that are running on Windows NT, unless you buy third party software or write a kernel mode driver. You can do port I/O from BCB if your program is running on Windows 95 or Windows 98. </P>+ w( C: x) I: I* O. o+ A
<>Explanation:8 y# e/ n, ^) [* x; f6 b
Intel protected mode processors provide four different privilege levels called ring 0, ring 1, ring 2, and ring 3. Ring 0 is the highest privilege level, and ring 3 is the lowest. Code that executes at ring 0 can call any assembly instruction and can access any I/O address. Code that runs at ring 3 is restricted. </P>
$ J1 Y& N- j% y5 n2 ]<>In Windows, only portions of operating system and device drivers run at ring 0. In order to keep programs from screwing up the system, Windows runs all user programs in ring 3. The Window's operating system doesn't utilize ring 1 or ring 2. Applications written with C++Builder, or any other compiler, will have ring 3 access rights, which means that their ability to do port I/O will be limited. </P>
; t4 y' t6 Z& [3 k9 e( t<>In order to keep ring 3 programs from doing port I/O, the i386 and subsequent processors maintain a bitmapped field for each program. Each bit in the bitmap corresponds to a port address. If a ring 3 program attempts to execute an IN or and OUT assembly instruction, the processor checks the bitmap to determine if the program can access that address. The processor generates an exception if it determines that a ring 3 program should not be accessing a port address. When the OS catches the exception that is generated by the processor, it's up to the OS to decide what should be done.</P>
1 [( O& Y8 Q3 Q& h<>If a ring 3 program attempts to access a hardware port, Windows 95 and Windows NT will react differently. Windows 95 responds by granting the ring 3 program access rights to the hardware by altering the bitmap field. It then executes the original port instruction that caused the exception to occur. The processor will not generate another exception if the ring 3 program tries to access the same port again. Windows NT is more strict, primarily because of security and robustness issues. If a hardware access exception is detected, Windows NT simply boots the offending ring 3 program off the system. The port instruction is not executed. </P>
! A4 m0 ~: N- E8 i+ B<>The port I/O dilemma; X, D" |; d& }7 Z/ E
Because Windows 95 allows port I/O, while Windows NT forbids it, the programmers at Borland were faced with an interesting challenge: what to do with the library functions inp, outp, inportb, outportb, etc. These functions are part of the C runtime library. The C run time library is built from source code that is written by Borland. Borland could have left the port functions in, but programs that call them would crash on windows NT. Conversely, removing the functions from the C run time library solves the crashing problem, but at the expense of preventing programmers from using the functions on Windows 95. </P>  y+ m4 u- \$ d  M
<>Borland decided to remove the port functions from the 32 bit version of their run time libraries. Perhaps they decided that removing the functions adhered better with win32 programming practices. Perhaps they were planning for the future (since Windows NT will eventually be the only OS offered by Microsoft). Perhaps they didn't realize that Windows 95 and Windows 98 would prevent hardware access, only to grant hardware access as soon as someone broke the rules (you must admit that Windows is someone half-baked in this regard). For whatever reason, Borland removed the port I/O functions from the C run time library, which means that you can't call inp and outp from your BCB programs. </P>
' p- R% w8 n* o; l<>Note: For the record, I must state that I agree with Borland's decision, but for a slightly different reason. In his book "Effective C++", Scott Meyers explains why programmers should prefer compile and link time errors to run time errors. A windows program that calls inp or outp will bomb out on Windows NT; hence, a run time error. Additionally, accessing the wrong port in Windows 95 could make the system unstable (more run time problems). Removing the functions may cause compile time headaches, but it also forces you to seek a more robust, run time stable solution. </P>
; `/ R( p* j! Q" ]<>Enough babble, how do I do port I/O from BCB?) }5 e5 o: D; N. Q3 Z
You have essentially three choices: either write a device driver, use someone elses device driver or find a replacement for inp and outp. If you don't need to run your program on Windows NT, then the easiest, and cheapest solution is to find a replacement for inp and outp. However, using a device driver is probably more robust, and it's the only way to run the program on NT. </P>. _% V5 s3 T2 {$ |' H
<>Finding a replacement for inp and outp </P>
& Z$ i; a; e; [- {( O<>With this strategy, your ring 3 program will simply call the assembly IN and OUT instructions. The processor will generate an exception, afterwhich, Windows 95 will alter your access rights. There are three ways to replace inp and outp: you can use the relatively unknown __emit__ macro, you can write your own version of inp and outp, or you can use my compiled version of inp and outp. </P>0 l0 S1 r, |# e5 T% ?
<>The __emit__ macro allows you to place raw bytes into your executable. With this strategy, you use __emit__ to manually insert the opcodes for the assembly IN and OUT instructions. </P>
4 Q! X6 N- \, f; t7 N* y7 P<>    #include &lt;dos.h&gt;</P>7 _( P0 h) l3 I) _+ k& u
<>    unsigned short inportw(unsigned short port)
  Q6 n7 l; I: Z1 i0 l! ]3 }    {1 N- g1 ~+ i& w6 s" E, T5 M3 C8 j% O
        _DX = port;- L3 M& U0 \: s: e4 n4 J3 l6 `
       __emit__(0x66, 0xED);  // 66ED = opcode for in ax,dx
7 t$ |- _5 {/ M3 m: k! u/ C       return _AX;
1 F: ?, l! w' I& l6 R3 T, o    }</P>- I0 E6 j  m0 [% m
<>    void outportw(unsigned short port, unsigned short value). v# G- r* p7 F
    {; _6 ?* Y4 l! S6 @8 G
        _DX = port;
3 X' S& f1 Z3 i  m. R/ e* S/ c( u        _AX = value;* `6 w' E  S1 [
        __emit__(0x66, 0xEF);  // 66EF = opcode for out dx,ax
8 Z/ H2 _7 p+ v% z" |* w: s    }</P>+ y9 J! H3 B- D3 M" L7 X" }5 }/ c
<>If you have TASM, Delphi, or C++Builder 3, you can write your own versions of inp and outp. They are very simple. Here are two samples to get you started. outp simply moves the port address into the DX register, moves the output value into AL or AX, and then calls the assembly OUT instruction. inp moves the address into DX, and then calls the IN instruction. The AL or AX register contains the return value. The port I/O package from the download page contains the source code for the port I/O routines that are not listed here. </P>5 f- z$ [# R# P" |9 P8 B6 z
<>    #include &lt;dos.h&gt;</P>& s2 C1 a; W) \2 z
<>    unsigned short inportw(unsigned short port)( @4 ?1 `3 I* y! `$ Q
    {
/ F) z$ X6 ^6 [: ^7 i        asm     mov     dx,port
$ Q9 Q- b" i0 d6 K: G. _% T        asm     in      ax,dx  Z6 n- I# e: F( ^6 H
        return _AX;% Y. C7 z8 ?. m2 D8 g& ?
    }</P>
; m, Z2 O$ l% W& `+ [8 C  W; n<>    void outportw(unsigned short port, unsigned short val)2 \: ^2 s: h8 v. i; _% F
    {
) y; U( |" I8 H5 v* L9 t2 B        asm     mov     dx, port
1 t7 u; G' n3 ], E6 H/ A        asm     mov     ax, val3 G6 v* [6 y9 @
        asm     out     dx, ax
6 B4 i/ T0 ]# q- a, b* C    }</P>8 r1 w8 [. ~$ S. I4 j$ V
<>
9 k5 |2 r' n% p. j$ P) iThe last way to replace inp and outp is to use a compiled module from someone else. This strategy really applies only to C++Builder 1. The downloads page contains a compiled OBJ that you can download and add to your BCB1 projects. The OBJ contains 32-bit versions of inp and outp that I produced with BC++ 5 and TASM 4. Simply add this OBJ to your project and you will be able to use inp and outp to your heart's delight. </P># O4 A" ~0 c; B$ w! v% f
<>Note: BCB 1.0 does not come with TASM, and without TASM it cannot process inline assembly in a C++ file. However, the pascal compiler can process inline assembly. This means that you can create a pascal unit that contains the inline assembly for the inp and outp functions. One common technique is to create a component in pascal that handles the port I/O. You can then add this component to a form and execute port I/O from your C++ code. If you still use C++Builder 1.0 and the thought of pascal leaves a bad taste in your mouth, then your only options are to write the routines using the __emit macro or use the compiled OBJ from the download page. </P>$ u7 [' \- U4 I& N
<>Note: The ports download on the download page contains a 32-bit OBJ for use with C++Builder 1.0. The download contains an OBJ because C++Builder 1.0 can't compile the inline assembly needed within the port I/O routines. The download also contains a C file that has the source code for the inline assembly I/O routines. If you have C++Builder 3, add this source file to your project. If you have C++Builder 1, add the OBJ file to your project. The OBJ file is not compatible with C++Builder 3. </P>  t) i/ I- M( b, V
<>Using someone elses driver </P>. d- I4 O: o$ c5 P9 m; K$ E
<>This strategy provides several benefits. First, without a driver, the very first I/O access from a ring 3 program will be delayed as Windows 95 alters the access bitmap. Secondly, the provider of the driver will hopefully provide a solution for both Windows 95, Windows NT, and future versions of Windows. </P>. ^+ d7 O; s4 {. @, j* I
<>BlueWater Systems has developed a product call WinRT that allows port access on both Windows 95 and Windows NT (if you purchase the correct options). WinRT provides port access routines that sit on top of device drivers. On Windows 95, the driver is a VxD. On Windows NT, the driver is a kernel mode driver. </P>
! ^2 J' l9 ^+ O, r: ~: k9 N<>Tetradyne Software also produce a port I/O solution for both Windows 95/98 and Windows NT. The product is called DriverX. One nice feature of DriverX is that it allows you to hook interrupts from your ring 3 program. </P>
+ j" J+ [) \9 n' F2 r2 Q4 A$ [<>There is another solution called TVicHW32. This product claims to work on both NT and Windows 95. It is cheaper than WinRT and DriverX. If you're looking for a free ride, you could give Keithley/MetraByte's DriverLINX a try. You can also try the TinyPort mini-driver or GiveIO solutions that are presented on Samuel Grimee's website. </P>0 P6 G4 _4 N% F' F0 F
<>Writing your own driver </P>
, g' i3 \) e( {6 @# G+ T<>I put this option last for a good reason: it's a bad option in most situations. Writing your own driver is costly because you must obtain the Windows 95 and Windows NT DDK's by subscribing to the MSDN. Then you have to learn how to write a device driver. Unfortunately, you have to learn three different device driver models: the VxD, the NT kernel mode driver, and the new Windows Driver Model introduced by windows 98 and NT 5. You will have to write three drivers, not one, and the concepts of each model are pretty much unique. </P>
  G2 H# |% C" ^2 R<>In my opinion, you should avoid this strategy unless you intend to someday make your living writing drivers. For the average GUI programmer, device drivers are a good item to avoid. Also keep in mind that this is a costly route to take. The MSDN is $500 or so. It's difficult, if not impossible, to create drivers with BCB due to the nature of the DDK (especially the NT DDK). This means you have to shell out $300 for MSVC++ (never mind the cost, does the average BCB programmer really want to use MSVC++ for anything?). You won't survive without at least $100 worth of device driver books. Plus, most programmers make use of third party driver tools, such as VToolsD and Driver::Works from VireoTools or WinDK from BlueWater Systems. You're talking $1000 just to get started. Now add at least 50 man-hours of labor at around $50/hr. The total cost of this option would probably exceed $3500 without much difficulty. This is a lot of money and time to spend if you don't intend to make writing device drivers part of your living. For most GUI programmers, writing your own driver for $3500 doesn't compare with the $100-$500 options that allow you to use someone elses driver. By using someone elses driver, you can avoid the headaches of writing a driver and get on with more profitable ventures. </P>: X- G8 _! X: \. |9 U) w. u% O

- B/ P  Q  L; U5 g6 H" i<P>Reference: Much of the technical information about port access in Windows 95 and Windows NT was provided by Karen Hazzah's "Port I/O Under Windows" article that appeared in the Jun/96 issue of Windows Developer Journal. </P>
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2025-5-12 15:27 , Processed in 1.280413 second(s), 51 queries .

回顶部