Table of Contents
Be Developer Classifieds are an opportunity for Be developers to tell each other about projects they're working on, are thinking about working on, or would like to work on. Here's your chance to request assistance on a project, or make your talents known to other projects. For more information, check out the Classified Ads section in the Registered Be Developer area. BeOS Job Listing: Tech WriterBeatWare, Inc., developer of essential software for the
BeOS, is looking for a Technical Writer to create web
graphics software documentation. If you are interested in
this exciting contract position and live in the Bay Area,
please contact John Barman at
BE DEVELOPER CONFERENCE: Register Now! Online registration is now open for the BeDC: Programming with the Media Kit that will take place April 9-10 in Palo Alto, California. Register before March 1, 1999 and receive a $20 discount! Get the scoop on registration, schedule, location, and travel information here: http://www.be.com/developers/developer_conference/
BE ENGINEERING INSIGHTS: An Introduction to Input Method Aware Views By Hiroshi Lockheimer - hiroshi@be.com
An input method is the software that converts keyboard events from one language into another. It is a translator of sorts: it enables the user to "type" in a language that doesn't mesh well with the traditional 100+ key keyboards. Take Japanese, for example. The Japanese language consists of a number of writing systems (sort of like alphabets). When combined, these alphabets contain literally many thousands of characters. Imagine a keyboard with that many keys! Input methods were created to work around this impracticality. For example, Be's new Japanese input method -- an installation option in R4 -- transliterates the Roman alphabet (the keys on your keyboard) into Japanese. The process for doing this is somewhat complicated, but that's another subject. This article is about what you need to do in order to support languages that require input methods. So, what do you need to do in order to capture the hearts of all those BeOS users out there in the rest of the world? The short answer: You don't need to do a thing! Sort of...
If your application's text entry needs are satisfied with
The first step is in the When the An input method-aware view receives key down messages in one
of two ways: 1) Through the standard - B_INPUT_METHOD_STARTED - B_INPUT_METHOD_STOPPED - B_INPUT_METHOD_CHANGED - B_INPUT_METHOD_LOCATION_REQUEST The
- be:string (a char*) - be:selection (two int32s) - be:clause_start (n-numbers of int32s) - be:clause_end (the same number of int32s as be:clause_start) - be:confirmed (a boolean) The string is what the user is currently entering. This is what you want to display at the current insertion point. BTextView highlights this text in blue to show that it is a part of a transitory transaction. There may be a selection within the blue portion. This is
expressed as a pair of In languages such as Japanese, a single sentence or phrase
is often separated into numerous clauses; Finally,
BMessage reply(B_INPUT_METHOD_EVENT); reply.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); BPoint screenDelta = ConvertToScreen(B_ORIGIN); screenDelta -= B_ORIGIN; for (int32 i = inlineStartOffset; i < inlineEndOffset; i = NextUTF8Character(i)) { reply.AddPoint("be:location_reply", LocalLocationOfCharacter(i) + screenDelta); reply.AddFloat("be:height_reply", HeightOfCharacter(i)); } theBeReplyToMessenger.SendMessage(&reply); The input method will take care of the rest for you. That was a quick overview of what you need in order to get started. Taking the time to implement an input method-aware view is an excellent first step towards making your product ready for the markets around the world. Good luck!
DEVELOPERS' WORKSHOP: Using and Writing Device Drivers on the BeOS By Jon Watte - hplus@be.com "Developers' Workshop" is a weekly feature that provides
answers to our developers' questions, or topic requests.
To submit a question, visit
[http://www.be.com/developers/suggestion_box.html].
This is second in a series of Developer Workshop
articles to help people program with the new Media Kit.
It was written by Be's Director of Media Technology.
The article first appeared on Rather than use a BeOS device driver directly, user-level
applications instead use some higher-level API which calls a
user-level add-on, which calls the driver. There's nothing,
however, that prevents an application from talking directly
to a driver just as an appropriate add-on would. Indeed, in
cases where there is no appropriate add-on API you have to
talk to the driver directly from an application. It's also
useful to talk directly to the driver while developing and
testing it. In this article, we'll call the entity
(application or add-on) that is using the driver a "client"
of the driver. The first thing you need to do is to find the device. The
driver will export one or more devices in subdirectories of
the Because most BeOS drivers support handling more than one
installed card of the same kind, the convention is to number
the installed cards, starting at 1. Thus, the first
installed Once you know what device you want to use, you should open
it using the You'll use this file descriptor to refer to the open device from now on. The file descriptor should be closed with
Many devices implement the The format of the data returned by the device varies with
the device; the default format of the sonic_vibes driver is
stereo 16-bit signed native-endian 44.1 kHz PCM sample data.
To play back this data using the Many devices do not work well with the simple Suppose we're using a video capture driver which implements
the following protocol: The client could then configure the driver like so: It would start video capture like so: It would wait for each frame to arrive like so: Last, it would stop the capture like so: In real life, a typical protocol is more capable, and thus
more complicated, than shown here, but it should be enough
to give you an idea of how the protocol between a user-level
client and a driver can be structured. OK, now that you know how to use a device driver, and have
some idea how to structure the protocol between the client
and the driver, it's time to get down and dirty with the
actual process of creating a driver. Creating a driver on
BeOS is done using ANSI C; the C++ language requires certain
support which is not available in the BeOS kernel
environment. If you already have a large C++ library that talks to your
hardware device and want to port it to BeOS, we suggest that
you make your driver very shallow and use it just to
read/write card registers and service interrupts, and put
all your C++ code in a user-level add-on. Some readers may
know "interrupts" by the name "IRQ"; we'll call them
"interrupts" because that's the terminology used by the BeOS
kernel kit. A driver is a loadable shared First, you have to decide what to call your driver and your
devices. Typically, one driver will service any number of
installed cards of the same type, and each of those cards
may cause the driver to publish multiple device names under
Typically, you'll name your driver something similar to the
name of the main chip serviced by the driver. The
Your device names will then be derived from the protocols
they implement, as well as the driver name. Thus,
sonic_vibes publishes devices in If your device is of some irregular kind, you can always
publish in The first function called in your driver, if you implement
and export it, is the Note: on BeOS, all the POSIX error codes (EXXX) are negative
numbers, so you should return them as-is to signify error. The next driver hook being called is Then, use the bus manager module to iterate over available
hardware, looking for instances of the hardware you support.
For each piece of hardware, make sure you enable its PCI bus
interface in the configuration registers if it isn't
already. Then allocate whatever memory you need to keep
track of the hardware and the devices that hardware will
cause to be published, and make sure the hardware is in some
safe, well-behaved state and not generating spurious
interrupts or other bad behavior. To allocate memory, use
If you find no hardware, return Next, the hook In Note that the names assume they live under " How does the devfs file system know which driver to open
when a program asks for the device named " Inside Thus, when a client calls open(" Not having to reboot for the new driver to be found is one
of my favorite features of BeOS for driver development. When a client decides to open one of your devices, the
kernel calls your A "device type" consists of a set of function pointers that
define the interface for a device. In If you don't implement Once you've returned a The kernel never dereferences the "cookie" value, so it can
be a pointer to some private data you Your Note that the device_hooks structure may acquire more
functions in later versions of BeOS. To tell the kernel what
version of the interface you were compiled with, you should
export an When the user is done with your device, he calls Once all outstanding I/O requests have returned from your
driver, the The Your interrupt handler is called whenever an interrupt on
your interrupt number occurs. Because of interrupt sharing,
your hardware may not be the hardware that generated the
interrupt. Your interrupt handler will be called on to
figure out whether the interrupt was caused by your
hardware, and if so, to handle it. The first thing you do in
the interrupt handler should be to read the appropriate
status register on your hardware, and if the interrupt was
not generated by your hardware, immediately return
If the interrupt was indeed generated by your hardware, you
can go ahead and handle the interrupt, and then return
While your interrupt handler runs, interrupts are turned
off. Thus, threads cannot be rescheduled, and other
interrupts cannot be handled. This means that your interrupt
handler should run as fast as possible. A typical interrupt
handler just acquires a spinlock (for mutual exclusion with
user-level threads), adjusts some internal data structure,
and quite possibly releases a semaphore which the user
thread ( The scheduling quantum on BeOS is 3000 microseconds. Thus,
if you release a semaphore without rescheduling, the longest
you may have to wait before a reschedule happens, and the
scheduler gets a chance to notice that your semaphore has
become available, and thus be able to schedule the thread
waiting on the semaphore, is 3 milliseconds. If this is too
long (for low-latency media devices like audio and MIDI, for
example) your interrupt handler routine can return the
special value Note that, because of multithreading and thread priorities,
your thread may not be the thread chosen to run just because
a reschedule happens. If you have really low latency
requirements, and can't afford to have lower-priority
threads come between your interrupt handler and your waiting
thread getting scheduled, you have to use real-time priority
for the thread waiting for the interrupt. Using real-time
priority for threads is dangerous, however, because they may
completely lock out other threads from the system, including
the graphics threads that draw to the screen, making the
system appear "hung" if your real-time thread does too much
work without synchronizing with a blocking primitive (like a
semaphore). Now that you know how your device is loaded and unloaded,
and how to handle interrupts generated by your hardware, you
can design the rest of your device API to be used by
user-level clients. The Your job inside the Please note that the buffer pointed at by "data" will
typically be in the user space of the team calling read().
It will typically be in discontiguous memory, and it will
not be locked in physical RAM. Thus, it is not accessible from an interrupt service routine, nor can you DMA directly
into it without first locking the buffer and getting the
physical memory mapping for it: The same rules apply for the An alternative is to use a contiguous buffer in kernel space
that you allocate and copy to/from in These kinds of decisions are easier if you're implementing a
device for which Be has defined a protocol, because then you
just follow the protocol. However, if you're implementing a
driver for a device for which there is no predefined
protocol, or if your device will have significantly better
performance using some other protocol, you'll have to design
the driver protocol on your own. The The You can start numbering your own operation constants from
In the example above, your device control hook can look like
this: Semaphores may cause a reschedule to another thread when
released. Thus, you should not release a semaphore from an
interrupt handler, or with interrupts disabled, without
passing the It is generally a good idea to put as much code as possible
at the user level, and make your driver as shallow as
possible even if you aren't forced to by porting C++ code.
The less code there is in the driver, the less locked memory
will be used, and the less code there is that may crash the
kernel. All of your driver's code and global/static data, as
well as all memory returned by Disabling interrupts is NOT sufficient to guarantee
atomicity, because on an SMP system, the other CPU may be
calling into your driver at the same time. For
synchronization with data accessed by interrupt handlers,
you have to use a spinlock. Spinlocks are the most primitive
synchronization mechanism available; basically they use some
atomic memory operation to test-and-set a variable. When the
test-and-set fails, the calling thread just keeps trying
(busy-waiting) until it succeeds. Thus, contention for
spinlocks can be quite CPU intensive. Therefore, they should
be used sparingly, and only to synchronize data that really
has to be touched by an interrupt handler (since semaphores
cannot be used by interrupt handlers). A spinlock is simply an If you fail to disable interrupts before acquiring the
spinlock, you'll deadlock on single-CPU machines, because
your interrupt handler may then be called (and try to
acquire_spinlock() your spinlock) while the regular thread
is holding the spinlock. That would be bad. Many people find it convenient to wrap spin-locking into two
general-purpose It's important to not disable interrupts for a long time. As
a general rule, no more than 50 microseconds is allowable.
If you disable interrupts for longer, you'll jeopardize the
overall performance of the BeOS and the machine it's running
on. Similarly, your interrupt service routine should not run
for more than 50 microseconds (and less is, of course,
better). You may find the lack of deferred procedure calls disturbing
if you come from some other driver architecture. However,
the time it takes for BeOS to service an interrupt, release
a semaphore, and cause a reschedule into a user-level
real-time thread is often less than the time it takes for
other operating systems just to handle the interrupt and get
to the deferred procedure call level. Thus, we prefer to do
what needs to be done in the user-level client threads that
call into the device hooks. If at all possible, let the user of your device spawn
whatever threads your device needs. Kernel threads are very
tricky and live by different, undocumented rules. If you
find a need for a periodic task, look into using timer
interrupts (available as of BeOS R4.1). Look for If you wish to use a kernel thread in your driver, there are
several pitfalls that make doing this a bad idea. The kernel
team is a team just like any other team, and your kernel
thread will have a stack in the upper half of the kernel
team address space. This stack (and stacks of other kernel
threads) is not accessible from user programs, and thus is
not accessible from device hooks called by user programs.
Only the lower half of the kernel team address space
( You also cannot use Again: Put the threads you need in the user-level client
(add-on, application, whatever). If the driver needs to
perform periodic tasks not in response to hardware
interrupts, use timer interrupts. They are even more
lightweight than threads, and have fewer of the problems
mentioned above. As with any interrupt routine, timer
interrupts still cannot access memory that is not in the
kernel space; thus if you need to write into user-supplied
buffers, do it in your driver Good luck!
(Due to a scheduling conflict, Jean-Louis Gassée's regular
column will not run in this week's Newsletter. Look for one
next week.)
1997 Be Newsletters | 1995 & 1996 Be Newsletters Copyright ©1999 Be, Inc. Be is a registered trademark, and BeOS, BeBox, BeWare, GeekPort, the Be logo and the BeOS logo are trademarks of Be, Inc. All other trademarks mentioned are the property of their respective owners. |