Issue 2-44, November 5, 1997

Be Engineering Insights: News from a NewBe

By Tim Black

When the elevator doors open, the first thing you notice is that no one seems to be home. You wander into a maze of cubes, intent on finding your elusive interviewer. Hard disk drives are stacked everywhere, like dirty dishes, and interface cards are scattered around like promo literature at a trade show. Computer systems are spilling their guts like dismembered remains on a Quake battlefield. A small camera stares at a wristwatch. You think to yourself, "I want some."

A few months later, deep in the driver dungeon, I'm surrounded by hardware and documentation, hard disks and driver cards, with the innards of several computers cluttering my desk. I've learned that sometimes pointing the small camera at a wristwatch really is the best thing to do with it.

While it's a lot of fun to get an Ultra Wide SCSI interface blasting over 14Mbytes/sec (with only a single drive), there are other tasks to perform, like writing newsletter articles. The first challenge of returning to the daylight world is using English, instead of C. The next is, What to write about? Since I spend my time with the SCSI drivers and kernel code, not with the bright and shiny APIs or application level object-oriented, buzzword stuff, I'll try to shed some light on writing device drivers.

SCSI device drivers! New Adapter card support for the BeOS! Have the e-mails of thousands been heard? In a word, yes.

So, if you can't wait for the driver demons to settle into tested configutations, if you want your new SCSI device driver in the BeOS *now*, and if you're just about crazy enough to write one yourself, read on.

The BeOS uses the CAM-SIM format for SCSI drivers, so before you write anything, you need to start with the ANSI document X3T10/792D "SCSI-2 Common Access Method." You also need the basic SCSI info, and this is in ANSI X3.131-1994 "Small Computer System Interface-2," http://www.symbios.com/x3t10/drafts.htm. Your card will hopefully be a PCI board, so you'll also need the PCI spec, http://www.pcguide.com/ref/mbsys/buses/types/pci.htm (this is just an overview, you might want to buy the full spec).

You'll also need complete hardware specs on the device you want to support. This can be a pain, because not all manufacturers are forthcoming about the details of their chips. For fear that a struggling developer might discover some deep dark trade secret, they'll do their best to hide critical information. They will make you sign papers, try to entrap you with contracts on shrink wrap. But you must press on and never lose hope, until the specs are yours.

Once you have the information you need, you'll be creating a loadable driver called a SIM. The driver will be placed in the /boot/beos/system/add_ons/kernel/cam directory.

I can't give you enough information in a newsletter article to write a real driver, but I can tell you how a SIM module is created for the BeOS. I can give you insight into a few of the internals, and tempt you to read all the other documentation I mentioned above (and what a geek feast this stack of docs can be!).

Start with a function called sim_install(). This is called during the boot process to initialize the basics of the driver and register the SIM with the XPT layer of the CAM driver (see the above-mentioned SCSI docs).

The BeOS does a lot of the PCI work for you. The bus is scanned early in the boot process; you can obtain info about the devices with the function get_nth_pci_info(). This is called in a loop near the top of sim_install to look at all the possible cards.

In this example I have a struc pointer called pA created to hold all the details of my current adapter. Yours will be different.

Let's RTFS, OK?

long sim_install (void)
{
  int            i,index;
  pci_info       *h;
  CAM_SIM_ENTRY  entry;

  /*get some space*/
  h = malloc(sizeof(pci_info));

  /*look at all possable cards*/
  for (i = 0; ; i++) {
    /*this will fail when we are done.*/
    if (get_nth_pci_info (i, h) != B_NO_ERROR) {
      break;
    }
    if (h->vendor_id == MY_VENDOR_ID) {
      pA->pPci_stuff = h;

      // here we get and lock the memory used by the PCI bus
      // card for IO. we must map a full page, even if the PCI
      // card only wants 256 bytes.

      pA->regs_area_id =
        map_physical_memory("MY registers",      /*name*/
        (void *)(h->u.h0.base_registers[0] &
           ~(B_PAGE_SIZE - 1)),     /*phy address*/
        B_PAGE_SIZE, /* override the true size (256) and get a page */
        B_ANY_KERNEL_ADDRESS,      /*address spec*/
        B_READ_AREA + B_WRITE_AREA,  /*protection*/
        &(pA->pAIC_regs));   /* **mapped_address */

      // this should never happen, but I /like/ to test for
      // things that should never happen.
      if ((int32)pA->regs_area_id < 0) {
        dprintf("****** Problems mapping aic
          device registers\n");
        RetVal = B_ERROR;
        break;
      }

      // since we mapped a whole page, we might need to
      // correct for offset within that page
      pA->pAIC_regs += (h->u.h0.base_registers[0] &
        (B_PAGE_SIZE -1))/sizeof(uint32);

      // now you get to write a lot of stuff for your
      // hardware. Here you malloc memory, create areas and
      // init your basic IO with the hardware.
      // After the hardware is verified as working you will
      // register two of your functions with
      // the OS. These functions conform to the CAM-SIM spec

      entry.sim_init = MY_Init_Func;
      entry.sim_action = MY_Action_Func;
      xpt_bus_register (&entry);
      /*this call is going to call entry.sim_init
        before it returns*/
  }
}

The Init and Action functions are outlined as follows:

long MY_Action_Func(CCB_HEADER *ccbh)
{
  static long (*sim_functions[]) (CCB_HEADER *, ADAPTER *) = {
    sim_invalid,      /*00 NOP - do nothing */
    sim_execute_scsi_io,  /*01 execute a scsi i/o command */
    sim_invalid,            /*02 get device type info */
    sim_path_inquiry,       /*03 path inquiry */
    sim_sim_release_queue,  /*04 release a frozen SIM queue */
    sim_set_async_callback, /*05 set async callback params */
    sim_invalid,      /*06 set device type info */
    sim_invalid,      /*07 reserved code */
    sim_invalid,      /*08 reserved code */
    sim_invalid,      /*09 reserved code */
    sim_invalid,      /*0a reserved code */
    sim_invalid,      /*0b reserved code */
    sim_invalid,      /*0c reserved code */
    sim_invalid,      /*0d reserved code */
    sim_invalid,      /*0e reserved code */
    sim_invalid,      /*0f reserved code */
    sim_abort,        /*10 abort the selected CCB */
    sim_reset_bus,    /*11 reset a SCSI bus PH_*/
    sim_reset_device, /*12 reset a SCSI device */
    sim_terminate_process  /*13 terminate an i/o process */
  };
  uchar op;

  ADAPTER *pA;

  pA = GlobalAdapterStorage[HOWEVER_YOU_MANAGE_IT];
  op = ccbh->cam_func_code;

  /*check for function codes out of range of dispatch table*/
  if (op >= sizeof (sim_functions) / sizeof (long (*)())) {

    /* check for our vendor-uniques (if any) here... */
    dprintf("**** AIC: SIM_ACTION called,
      invalid function 0x%x\n",op);
    ccbh->cam_status = CAM_REQ_INVALID;
    return -1;
  }

  return (*sim_functions [op]) (ccbh,pA);
}

Creating all these internal functions is left as an exercise for the crazed driver writer.

long MY_Init_Func (void)
{
  int      i;
  int      size;
  uint*    boot_data;
  vuchar*  dev_base_pci; /* -> registers, viewed from pci */
  ADAPTER  *pA;

  pA = GlobalAdapterStorage[HOWEVER_YOU_MANAGE_IT];
  dev_base_pci = (vuchar *)pA->pAIC_regs;

  // this ram_address() function is to adjust for io mapping
  // offsets in hardware like the BeBox.
  pA->HostBase = (long) ram_address (0);

  // if your init function returns good results, save the
  // configuration into the PCI space.
  if(InitAdapter(pA)){
    write_pci_config (pA->pciLocation.pciAddress.busNumber,
      pA->pciLocation.pciAddress.deviceNumber,
      pA->pciLocation.pciAddress.functionNumber,
      PCI_command, 2,
      PCI_command_io | PCI_command_memory |
        PCI_command_master | PCI_command_parity |
        PCI_command_serr);

    // you will most likely need some sem's to control
    // access to hardware, here is where you create them.

    if ((pA->hw_sem = create_sem(1, "My_scsi_hw")) < 0)
      return -1;

    if ((pA->int_sem = create_sem(1, "My_scsi_int")) < 0)
      return -1;

    // now try to control your device, and set some values
    // if all is well (or not)

    if (YOUR_HARDWARE_IS_NOT_OK){
      dprintf("***** hardware failure. abandoned adapter.");
      return B_ERROR;

    }else{
       /* get host adapter interrupt*/
       pA->intline = pA->pPci_stuff->u.h0.interrupt_line;

      /* set up our interrupt handler */
      set_io_interrupt_handler
        (pA->pPci_stuff->u.h0.interrupt_line,
        IrtFuns[AdptNum].Initrr, NULL);
      enable_io_interrupt
        (pA->pPci_stuff->u.h0.interrupt_line);

      // here is where you would init your buffer pools and
      // setup other driver items.

      // now scan the SCSI bus and save the results in some
      // local struct. (to be used by functions in the SIM
      // spec)

      return B_NO_ERROR;
    }
  }else{
    return B_ERROR;
  }
}

If anyone has an inside track on some needed device, and wants more detail on driver creation, send e-mail and I'll provide (some) support. While we are limited in the amount in time we can give to support, drivers are a high priority (especially on the Intel side).

I'm getting an urge to code, so that's all the English I have for now (more next time).

(A creaking sound is heard as a trap door in the floor opens up. Tim slowly walks down a cobweb-covered stairway, ducking to avoid the rusty pipes and dangling wires. Off in the distance a dprintf is heard mumbling about "hardware failures." The trap door closes with a thud.)


Be Engineering Insights: How to Finish a Product

By Dave Johnson

They say that the first 90% of development of an application might take 4 or 5 months but that the second 90% can take a year. So software that is 90% completed really has only a little more value than all that software you never got started on in the first place. In the software business the only thing that is really worth a darn is a completed product. In this article I'll offer some suggestions for shortening the second 90% and getting your application out the door to the customer.

I used to be in the videogame business, which can be very unforgiving. It's driven by two CES's (Consumer Electrionics Shows) each year, plus the Christmas season. You show your new videogame prototype at the January CES. At the June CES you either show a second game or take orders on the nearly completed first one. In late August or early September you ship, because in the retail business that is Christmas. Period.

Alternatively, you become a realtor or sell cars or something, but you don't get to be a game designer anymore. As a result of working under this relentless schedule, I developed some techniques that helped me finish and ship applications. These are more psychological than technical, but I've found that they can play a big part of getting a product out the door.

Design one program at a time

One thing I notice as I survey Be's developer database is that a lot of developers are SO excited about all the things the BeOS can do that they are working on several projects at once! Inevitably, this divides their concentration and attention. Bouncing between applications can take much longer than doing them one at a time. Pick one and get it done.

Sometimes working on more than one project at a time is a way to keep from getting bored. Let me suggest a better way: Concentrate on one project, finish it, get some *money* from customers and use the *money* to keep from getting bored.

Stop designing your product and start debugging it

This suggestion violates some rules because it sounds like I'm telling you to just wing it. But I've learned that it fits my style better to get something up and running as soon as I can, and then use it, refine it and debug it instead of continuing to design it. Once I start debugging and finishing, I'm over the hump.

I know this is a psychological thing, but it has benefits that you don't get when your app isn't up and running. In the first place you discover things that don't work as well as you thought they would, and you have to make changes. You learn which changes have to be made much sooner than if you keep on designing for a long time. Also, in the debugging state you're more resistant to adding features. Why do I think this is a good thing? Read on.

Take out all the unfinished features you are working on and ship it

Sure, lots of great features will be good for your customers. But your program is not helping yor customers *at all* until it is in their hands. This is a key point. You think you are doing the right thing by perfecting your product and making it the greatest thing ever written. But you aren't doing your customers *any* good if they don't have something in their hands that they can use. So *ship it*! Perfection works against you if it keeps you from delivering a usable product.

And remember, while you're working on several products, or trying to perfect one, the competition is finishing *its* third-rate product! It could wind up in the customer's hands instead of yours. Certainly theirs isn't going to be as good as yours. And it's not going to have all those great features you're still working on. But that's why *it* got *done* and yours didn't. So beat the competition: Finish the thing and ship it. Stop perfecting it.

Think a lot about version 2

No, I actually don't mean here to plan ahead and design your objects for extensibility. Of course you want to do that. I mean every time you think you want to add a feature or "improve" something, remember that there will be a version 2 and you can add to that the glitzy features which are hanging you up now. I know I'm repeating myself, but this is important enough to say again: Stop adding stuff, stop improving it, limit it, and get it out the door.

The customer will tell you what to add, and then pay you for it!

Whether or not you perfect it now, in the end the customer is going to tell you what to add—and you will often find out that you did a lot of work for nothing. Get your product out to the customer fast so you can hear about what should be in the next version, instead of deciding for the customer, adding it, and holding up the product forever. Letting the customer drive the product's features in this way means you are delivering it sooner and learning what the customer wants.

And, frankly, you're going to make money on upgrades. This is the new subscription model for software revenue. You get your product into as many hands as possible with a low introductory price and then you sell upgrades. By pushing things into the next version you have an upgrade path which leads to a revenue stream from upgrade sales.

I hope this helps. Now, what I want to see from you all is a huge outpouring of products for the BeOS. I'll consider all of them to be inspired by this article. Thank you.


Developers' Workshop: Updates from DTS

By Brian Mikol

"Developers' Workshop" is a new weekly feature that provides answers to our developers' questions. Each week, a Be technical support or documentation professional will choose a question (or two) sent in by an actual developer and provide an answer.

We've created a new section on our website. Please send us your Newsletter topic suggestions by visiting the web site at: http://www.be.com/developers/suggestion_box.html.

Having been reminded it was my turn to contribute a newsletter article, I thought I would take this opportunity to bring you all up to speed about what's going on in the "mothership" regarding Developer Support.

To begin with, we have two new people with whom all you developers will be coming into contact. Doug Wright has joined DTS and is feverishly pounding out sample code when not answering devsupport e-mail. The other addition is Melanie Walker, our new "Web Diva." Melanie has also taken over the approval and maintenance of BeWare submissions. Be forewarned, she is not as lenient as I was...

We've also changed some operational details. Although this bit of news is a little old, we have reorganized and cleaned up the FTP site. Sample code is now found in one place on the ftp site: ftp://ftp.be.com/pub/samples/. This directory is futher broken down into which version of the BeOS the sample code is from—something I imagine will fade as developers no longer need code for a DR7 application.

Additionally, all BeWare that hasn't been updated to work with Preview Release has been moved into its own directory tree to prevent confusing naming conventions: ftp://ftp.be.com/pub/obsolete/.

The BeOS updates have earned their own directory:
ftp://ftp.be.com/pub/beos_updates/. Please note the developers/ subdirectory—this is a place to hold developer-specific software (such as the alpha version of the 3d Kit).

And lastly (in regards to the FTP site), we have now instituted a .zip/.pkg-only archive rule. That is, all BeWare submissions are to be sent as either a zipped directory containing your software or as a SoftWare Valet .pkg archive. (Unfortunately, the Webmaster has fallen behind in updating the online copy of the BeWare submission guidelines, but if you want an updated copy for your records, send e-mail ftparchive@be.com.) [Webmaster's Note: Hint taken, Brian! The Uploading Guidelines have now been updated.]

The reason for this change is that both these archive formats retain the attribute settings of the software they contain (and you'll notice the archives' attributes themselves are preset in the FileTypes Preferences). Why do we want this? To enable a better user experience not only with the BeOS, but with third-party BeWare software as well! It's true what they say about first impressions, after all.

On the webscene, we've been getting some pretty positive comments about the Sample Code section that Geoff worked up before he left: http://www.be.com/developers/sample_code/index.html. The main idea is once again to have _one_ central place to go to for sample code (it mirrors the structure of the pub/samples/ subdirectory tree). There's still a lot of work to be done on it, but as people are pretty happy with it, we'll keep plugging away.

To finish, I would like to share some things we're planning and hope to implement soon.

First, we are looking to hire another DTS Engineer in addition to a DTS Manager: http://www.be.com/aboutbe/jobs/index.html. I guess Doug and I are too unruly for Ed and Mel to handle by themselves. :-)

Also, we are looking to get back into the habit of holding regular Developer Kitchens, especially with the Intel version coming out soon (Got questions about the Intel release? Check out the Intel FAQs: http://www.be.com/support/qandas/intel.html). Stay tuned to the developer section of the website for updates on that: http://www.be.com/developers/index.html.

That's pretty much it for now. I'm sure I'm forgetting something (I always do :-), but those are the top issues that I wanted to share with you all. Handling increased mail from Customer Support has been taking up most of my time, but I am still intently watching the new Registered Developer applications roll in (Got questions about what we're looking for in our applications? Check out the guidelines: http://www.be.com/developers/devprogramapp.html and, for my own personal input, take a peek at my last newsletter article: http://www.be.com/aboutbe/benewsletter/Issue80.html#Insight2). Until next time...


Shipping News

By Jean-Louis Gassée

We've been shipping our latest BeOS release, PR 2, for about two weeks now. As a result, we're starting to get feedback from developers and users and it is generally good, with the "generally" referring to fixes and improvements we need to make in future releases, or in updates to be posted on our site.

As with each release, we have been living in fear of some horrible oversight in our design or testing procedures, soon exposed by an expert user or, even worse, an innocent one. One of the classic problems is testers become overly competent users; as hard as they may try, they acquire some unconscious knowledge of the location of land mines—and avoid the area. "Why did you do that?" "I don't know", replies the dangerous user. In the same vein, knowing too much can lead to writing upgrading instructions that mislead users. It can and we did. So, with our apologies, we posted a "clarification" in http://www.be.com/support/preview/upgrading_to_pr2.html.

The previous release, PR 1, was extremely ambitious, it introduced many new features and a major rewrite of the file system. As a result, we also introduced many new bugs and stability wasn't as good as we—and, more importantly, developers and users—had hoped for. Fixes were quickly posted as updates on our site and stability, more than features, was the most important goal for PR2. So far, it looks like we've made progress. I'm being careful here, in the early days of an OS there always exists the potential for new execution paths to be discovered as leading to a crash.

Many readers have probably seen the ZD Net BeHive report on PR 2. It can be found at http://www3.zdnet.com/mac/behive/hacker15.html and is worth reading, not just for the comments on PR2 stability itself, but also for more application shipping news. There is even an interesting discussion of r¡ design's work and some of the unique capabilities of the BeOS it demonstrates, in this case BMessages. As we offer better stability and BeOS developers start to show what the platform can do, we are getting calls for more ways to utilize the basic capabilities of our product. As a result, we are sitting with existing BeOS developers and gathering their suggestions for better media capabilities in upcoming revisions.

As we do this, we're also gearing up to help BeOS developers make the transition to the Intel Architecture version of the BeOS. By early December, we will offer limited facilities to recompile and test already shipping BeOS applications. We all want a running start on Intel—pun unintended.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.