bool uplink_packet( int port, byte *buffer ) { byte length; CALL_MSG("starting uplink_packet()", ++pclta_call_level); write_byte_wait( port, CMD_ACK ); read_byte_wait( port ); // dummy *buffer++ = length = (read_byte_wait( port )); //first byte is length DEBUG_MSG( "in uplink_packet() length = %d", length ); if( length == 0 ) { RETURN_MSG("uplink_packet() LENGTH=0", pclta_call_level-- ); return false; // drop it } while( length-- ) { *buffer++ = read_byte_wait( port ); #ifdef DEBUG if((int)(buffer-1)%8 == 0) // formating debug output.. DEBUG_MSG(" " ); printk( "[%2x] ", *(buffer-1) ); #endif CALL_MSG("downlink_packet()", ++pclta_call_level ); } RETURN_MSG("finishing uplink_packet()", pclta_call_level-- ); return true; }
int close_pclta( struct inode *inode, struct file *file ) { struct pclta_device *device = pclta_device_table[MINOR(inode->i_rdev)]; CALL_MSG("close_pclta()", ++pclta_call_level ); if( device == NULL ) { RETURN_MSG("close_pclta() ENXIO", pclta_call_level-- ); return -ENXIO; // no such device } if( device->state == Offline ) { RETURN_MSG("close_pclta() already closed", pclta_call_level-- ); return 0; // device already closed } // karl removed this for 2.4 kernel 30 July 2001 // if( file->f_count >1 ) { // RETURN_MSG("close_pclta() EBUSY", pclta_call_level-- ); // return -EBUSY; // not the last process // } device->state = Offline; init_hw( device->base_address, 0x00, device->txcvr_clock ); // turn off interupts close_device( device ); MOD_DEC_USE_COUNT; RETURN_MSG("close_pclta()", pclta_call_level-- ); return 0; }
void cleanup_hw( struct pclta_device *device ) { int io; CALL_MSG("cleanup_hw()", ++pclta_call_level ); // don't bother if device undefined if( device == NULL ) { RETURN_MSG("cleanup_hw() DEV=NULL", pclta_call_level-- ); return; } io = device->base_address; // reset internal interrupt register write_byte_wait( io, CMD_XFER ); write_byte_wait( io, 2 ); write_byte_wait( io, niIRQENA ); write_byte_wait( io, IRQPLRTY ); // release I/O region and interrupt release_region( io, 4 ); DEBUG_MSG("Freeing up Interrupt %d", device->interrupt); free_irq( device->interrupt,device ); // free up other resources remove_device( device ); RETURN_MSG("cleanup_hw() CLEANED", pclta_call_level-- ); }
bool open_device( struct pclta_device * device ) { CALL_MSG( "Starting open_device()", ++pclta_call_level ); // allocate and initialize buffers device->rx = kmalloc( sizeof(struct pclta_packet_buffer), GFP_KERNEL ); if( device->rx == NULL ) { RETURN_MSG( "open_device() ERROR= device->rx == NULL", pclta_call_level-- ); return false; } device->tx = kmalloc( sizeof(struct pclta_packet_buffer), GFP_KERNEL ); if( device->tx == NULL ) { kfree( device->rx ); RETURN_MSG( "open_device() ERROR= device->tx == NULL", pclta_call_level-- ); return false; } init_buffers( device->rx ); DEBUG_MSG("RECEIVE BUFFER"); print_buffer(device->rx); init_buffers( device->tx ); DEBUG_MSG("TRANSMIT BUFFER"); print_buffer(device->tx); // set initial state of device device->restart_uplink = false; device->pclta_wait_queue = NULL; // last_packet_read_complete=true; // for incomplete reads RETURN_MSG( "open_device() SUCCESS", pclta_call_level-- ); return true; }
bool wait_uplink_buffer( int port, int sec100, byte *buffer ) { int count=0; CALL_MSG("wait_uplink_buffer()", ++pclta_call_level ); // initialize timeout timer setup_timeout( sec100 ); // wait for uplink buffer, or timeout while( !(inb_p(status_reg(port)) & ULREADY) && !pclta_timeout ) { count++; } // uplink buffer ready, kill timeout timer del_timer( &pclta_timer_list ); // unsuccessful if timed out if( pclta_timeout ) { RETURN_MSG("wait_uplink_buffer() TIMEOUT", pclta_call_level-- ); return false; } // otherwise, ready to send packet to device uplink_packet( port, buffer ); DEBUG_MSG("Count = %d",count); RETURN_MSG("wait_uplink_buffer()", pclta_call_level-- ); return true; }
struct pclta_device * create_device( int port, int irq, byte txcvr_clock ) { struct pclta_device *device; CALL_MSG( "create_device()", ++pclta_call_level ); // allocate descriptor space device = kmalloc( sizeof(struct pclta_device), GFP_KERNEL ); if( device == NULL ) { RETURN_MSG( "create_device() kmalloc error", pclta_call_level-- ); return NULL; } else { device->interrupt_queue = kmalloc( sizeof( struct tq_struct ), GFP_KERNEL ); if( device->interrupt_queue == NULL ) { kfree( device ); RETURN_MSG( "create_device() kmalloc error", pclta_call_level-- ); return NULL; } } device->base_address = port; device->interrupt = irq; device->state = Offline; device->rx = device->tx = NULL; // initialize these later device->txcvr_clock = txcvr_clock; // initialize interrupt task queue device->interrupt_queue->routine = (void *)pclta_service; device->interrupt_queue->sync = 0; RETURN_MSG( "create_device()", pclta_call_level-- ); return device; }
void close_device( struct pclta_device * device ) { CALL_MSG( "close_device()", ++pclta_call_level ); if( device->state == Offline ) { RETURN_MSG( "close_device()", pclta_call_level-- ); return; } kfree( device->rx ); kfree( device->tx ); device->tx = device->rx = NULL; // wake_up_interruptible( &device->pclta_wait_queue ); // karl thinks this not needed removed 1 aug 2001 RETURN_MSG( "close_device()", pclta_call_level-- ); }
int open_pclta( struct inode *inode, struct file *file ) { struct pclta_device *device = pclta_device_table[MINOR(inode->i_rdev)]; file->private_data = device; // file->f_op=&pclta_fops; karl test 13/07/2000 CALL_MSG("open_pclta()", ++pclta_call_level ); if( device == NULL ) { RETURN_MSG("open_pclta() ENXIO", pclta_call_level-- ); return -ENXIO; // no such device } if( device->state != Offline ) { RETURN_MSG("open_pclta() EBUSY", pclta_call_level-- ); return -EBUSY; // device busy } if( !open_device( device ) ) { RETURN_MSG("open_pclta() ENOMEM", pclta_call_level-- ); return -ENOMEM; // out of memory } // program interrupt request line // outb_p(irq_mask[device->interrupt], selirq_reg(device->base_address) ); //removed 07/07/200 karl. added init_hw below DEBUG_MSG("Base Addy=0x0%x ; IRQ=%d ; IRQ MASK = 0x0%x \n",device->base_address, device->interrupt ,pclta_irq_mask[device->interrupt]); init_hw( device->base_address, pclta_irq_mask[device->interrupt], device->txcvr_clock ); if( ! wait_reset(device->base_address, 500 ) ) { VERBOSE_MSG( "error(%d) PCLTA_LRESET.\n", PCLTA_LRESET ); return -EBUSY; } // waiting to leave reset state device->state = Idle; //enable_irq( device->interrupt ); // karl's test 07/07/2000 MOD_INC_USE_COUNT; RETURN_MSG("open_pclta() OK", pclta_call_level-- ); return 0; }
bool wait_reset( unsigned int port, int sec100 ) { CALL_MSG("wait_reset()", ++pclta_call_level ); setup_timeout( sec100 ); while( ( inb_p(status_reg(port)) & RESET ) && !pclta_timeout ); del_timer( &pclta_timer_list ); if( pclta_timeout ) { RETURN_MSG("wait_reset() false", pclta_call_level-- ); return false; } RETURN_MSG("wait_reset() true", pclta_call_level-- ); return true; }
bool write_byte_timeout( int port, byte data_byte, int sec100 ) { CALL_MSG("write_byte_timeout()", ++pclta_call_level ); setup_timeout( sec100 ); while( ( inb_p( status_reg(port) ) & _READY ) && ( ! pclta_timeout ) ); if( ! pclta_timeout ) outb_p( data_byte, data_reg(port) ); del_timer( &pclta_timer_list ); if( pclta_timeout ) { RETURN_MSG( "write_byte_timeout() false", pclta_call_level-- ); return false; } RETURN_MSG( "write_byte_timeout() true", pclta_call_level-- ); return true; }
void cleanup_module( void ) { unsigned int i; CALL_MSG("cleanup_module()", ++pclta_call_level ); for( i=0; i<MAX_DEVICES; i++ ) cleanup_hw( pclta_device_table[i] ); unregister_chrdev( pclta_major, pclta_device_name ); RETURN_MSG("cleanup_module()", pclta_call_level-- ); }
//////////////////TEST FUNCTION void print_buffer( struct pclta_packet_buffer * packet_buffer ) { unsigned int i; CALL_MSG( "print_buffer()\n", ++pclta_call_level ); DEBUG_MSG("Buffer head= %ud tail= %ud\n",(unsigned int) packet_buffer->head,(unsigned int) packet_buffer->tail); for( i=0; i<PACKETS_PER_BUFFER; i++ ) { DEBUG_MSG("PB: %d ; Busy= %d ; L= %d ; d0= %x ; d1= %x ; d2= %x \n",i ,packet_buffer->buffer[i].busy,packet_buffer->buffer[i].length,packet_buffer->buffer[i].data[0],packet_buffer->buffer[i].data[1],packet_buffer->buffer[i].data[2]); } // start at beginning of buffer RETURN_MSG( "print_buffer()", pclta_call_level-- ); }
void downlink_packet( int port, byte * buffer ) { byte length = *buffer; //length is first byte in buffer. CALL_MSG("downlink_packet()", ++pclta_call_level ); DEBUG_MSG("IN downlink_packet() LENGTH= %d",length); write_byte_wait( port, length ); while( length-- ) write_byte_wait( port, *(++buffer) ); RETURN_MSG("downlink_packet()", pclta_call_level-- ); }
void pclta_start_downlink( struct pclta_device *dev ) { struct pclta_packet *packet_buffer; unsigned char ni_cmd, buff_p, status; CALL_MSG("Starting pclta_start_downlink()", ++pclta_call_level ); // DEBUG_MSG if( dev->state == Idle ) { DEBUG_MSG("pclta_start_downlink () Device is idle. checking if busy"); packet_buffer = dev->tx->tail; if( packet_buffer->busy ) { ni_cmd = packet_buffer->data[0]; DEBUG_MSG("NICOMMAND = [0x%2x]",ni_cmd); if( ni_cmd == niSERVICE ) { buff_p = DLPBA; ni_cmd = niCOMM; } else { buff_p = ni_cmd & niPRIORITY ? DLPBA : DLBA; ni_cmd &= NI_Q_CMD; } status = inb_p( status_reg(dev->base_address) ); if( ni_cmd == niCOMM || ni_cmd == niNETMGMT ) { if( status & buff_p ) dev->state = Transfer; } else dev->state = Transfer; if( dev->state == Transfer ) { if( status & RESET ) dev->state = Idle; else { DEBUG_MSG( "xfer_start, " ); write_byte_wait( dev->base_address, CMD_XFER ); DEBUG_MSG( "xfer_done, base addy = 0x0%x ",dev->base_address ); } } } } RETURN_MSG("Finishing pclta_start_downlink()", pclta_call_level-- ); }
void init_buffers( struct pclta_packet_buffer * packet_buffer ) { unsigned int i; int buffer_index; CALL_MSG( "init_buffers()", ++pclta_call_level ); for( i=0; i<PACKETS_PER_BUFFER; i++ ) { packet_buffer->buffer[i].next = & packet_buffer->buffer[(i+1)%PACKETS_PER_BUFFER]; packet_buffer->buffer[i].busy = false; packet_buffer->buffer[i].length = 0; for (buffer_index=0; buffer_index < MAX_PACKET_SIZE; buffer_index++) // default data to 0 packet_buffer->buffer[i].data[buffer_index] = 0; } // start at beginning of buffer packet_buffer->head = packet_buffer->tail = &packet_buffer->buffer[0]; RETURN_MSG( "init_buffers()", pclta_call_level-- ); }
void init_hw( int port, byte irq, byte txcvr_clock ) { CALL_MSG("init_hw()", ++pclta_call_level ); DEBUG_MSG("PROGRAM IRQ LINE Writing 0x0%x to 0x0%x",irq, selirq_reg(port)); // program interrupt request line outb_p( irq, selirq_reg(port) ); // reset device DEBUG_MSG("RESET device with txcvr_clock Writing 0x0%x to 0x0%x",txcvr_clock, clkrst_reg(port)); outb_p( txcvr_clock, clkrst_reg(port) ); DEBUG_MSG("UNREST Device Writing 0x0%x to 0x0%x", PCLTA_RESET | txcvr_clock, clkrst_reg(port) ); outb_p( PCLTA_RESET | txcvr_clock, clkrst_reg(port) ); DEBUG_MSG("ACK IRQ hardware Writing 0x0%x to 0x0%x",~CLRIRQ, clrirq_reg(port) ); // acknowledge IRQ hardware if( irq ) outb_p( ~CLRIRQ, clrirq_reg(port) ); RETURN_MSG("init_hw()", pclta_call_level-- ); }
int email_grammar_checker(char *string) { int i=0,j=0; int val_start,val_end; int iteration_values[2][2]={{0,0},{0,0}}; int len=0; //length of string int position_at=0; //location of at int is_dot=0; //found dot? //rule 3 int count_at=0; int pass=SW_FAIL; //pass variable (default:FAIL) int char_count; //the number of letter char *p; char prev_ch=0; /* 1) an email address has two parts, Local and Domain, separated by an '@' char 2) both the Local part and the Domain part consist of a sequence of Words, separated by '.' characters 3) the Local part has one or more Words; the Domain part has two or more Words (i.e. at least one '.') 4) each Word is a sequence of one or more characters, starting with a letter 5) each Word ends with a letter or a digit 6) between the starting and ending chars, there may be any number of letters, digits or hyphens ('-') */ //--------------------------------------------------------------------------------------- //RULE 1 //1) an email address has two parts, Local and Domain, separated by an '@' char //String is not safisfied with rule 1( '@' should be located between Local and Domain.); p=string; len=0; count_at=0; pass=SW_FAIL; while(*p) { if(func_is_at(*p)== IS_TRUE) { pass=SW_PASS; //this rule is valid because of the presence of @. position_at=(int)(p-string);//get position of '@'. count_at++; } p++; len++; } if(count_at>1) // abc@[email protected] pass=SW_FAIL; if(pass==SW_FAIL) RETURN_MSG("err:r1",RET_INVALID); //Local Checking scope iteration_values[0][0]=0; iteration_values[0][1]=position_at; //Domain Checking scope iteration_values[1][0]=position_at+1; iteration_values[1][1]=len; pass=SW_PASS; //---------------------------------------------------------------------------------------- //RULE 2 //2) both the Local part and the Domain part consist of a sequence of Words, separated by '.' characters //Words should be separated by '.'. So, ".." is not permitted. for(j=0;j<2;j++) { val_start=iteration_values[j][0]; val_end=iteration_values[j][1]; if(func_is_dot(string[val_start])== IS_TRUE) // [email protected] =>FAIL pass=SW_FAIL; else if(func_is_dot(string[val_end-1])== IS_TRUE) // [email protected] =>FAIL pass=SW_FAIL; if(pass == SW_FAIL) RETURN_MSG("err:r2-0",RET_INVALID); prev_ch= string[val_start]; for(i=val_start+1;i<val_end;i++) { if(prev_ch==string[i]) if(func_is_dot(prev_ch)== IS_TRUE) // [email protected] { pass=SW_FAIL; break; } prev_ch=string[i]; } if(pass == SW_FAIL) RETURN_MSG("err:r2-1",RET_INVALID); } //---------------------------------------------------------------------------------------- //RULE 3 //3) the Local part has one or more Words; the Domain part has two or more Words (i.e. at least one '.') //Local Checking char_count=0; for(i=0;i<position_at;i++) { if(func_is_alphabet(string[i]) == IS_TRUE) char_count++; } if(char_count<1) pass=SW_FAIL; if(pass == SW_FAIL) RETURN_MSG("err:r3-1",RET_INVALID); //Domail Checking char_count=0; is_dot=0; for(i=position_at+2;i<len;i++) { if(func_is_alphabet(string[i]) == IS_TRUE) char_count++; else if(func_is_dot(string[i]) == IS_TRUE) is_dot=1; //[email protected] } if(char_count<2 || is_dot==0) // haha@ad pass=SW_FAIL; if(pass == SW_FAIL) RETURN_MSG("err:r3-2",RET_INVALID); //---------------------------------------------------------------------------------------- //RULE 4 //each Word is a sequence of one or more characters, starting with a letter for(j=0;j<2;j++) { val_start=iteration_values[j][0]; val_end=iteration_values[j][1]; prev_ch=string[val_start]; if(func_is_alphabet(prev_ch) == IS_FALSE) //[email protected] pass=SW_FAIL; else for(i=val_start+1;i<val_end;i++) { if(func_is_dot(prev_ch)== IS_TRUE) { if(func_is_alphabet(string[i]) == IS_FALSE) // [email protected] { pass=SW_FAIL; break; } } } if(pass == SW_FAIL) RETURN_MSG("err:r4",RET_INVALID); } //---------------------------------------------------------------------------------------- //RULE 5 //5) each Word ends with a letter or a digit for(j=0;j<2;j++) { val_start=iteration_values[j][0]; val_end=iteration_values[j][1]; if(!((func_is_alphabet(string[val_end-1]) ==IS_TRUE) || (func_is_number(string[val_end-1])==IS_TRUE))) // abc [d] @abc.com is a letter or a digit pass=SW_FAIL; else { prev_ch=string[val_start]; for(i=val_start+1;i<val_end;i++) { if(func_is_dot(string[i]) == IS_TRUE) // abc[.]@abc.com { if(!((func_is_alphabet(prev_ch) == IS_TRUE) || (func_is_number(prev_ch) == IS_TRUE))) { pass=SW_FAIL; break; } } prev_ch=string[i]; } } if(pass == SW_FAIL) RETURN_MSG("err:r5",RET_INVALID); } //---------------------------------------------------------------------------------------- //RULE 6 //6) between the starting and ending chars, there may be any number of letters, digits or hyphens ('-') for(j=0;j<2;j++) { val_start=iteration_values[j][0]; val_end=iteration_values[j][1]; if(func_is_dash(string[val_start])== IS_TRUE || func_is_dash(string[val_end-1]) == IS_TRUE) // [email protected] pass=SW_FAIL; else { prev_ch=string[val_start]; for(i=val_start+1;i<val_end;i++) { if(func_is_dot(prev_ch) == IS_TRUE)// [.][email protected] { if(func_is_dash(string[i]) == IS_TRUE) // .[-][email protected] { pass=SW_FAIL; break; } } else if(func_is_dot(string[i]) == IS_TRUE) // abc-[.][email protected] { if(func_is_dash(prev_ch) == IS_TRUE) // ab[-][email protected] { pass=SW_FAIL; break; } } prev_ch=string[i]; } } if(pass == SW_FAIL) RETURN_MSG("err:r6-1",RET_INVALID); } //------------------------------------------------------------------------------------------ return RET_VALID; }
//--------------------------------------------- // read_pclta() ssize_t read_pclta( struct file *dev_file, char * buffer, size_t count, loff_t * offset ) //long read_pclta(struct inode* dev_inode, struct file *dev_file, char *buffer, unsigned long count) //read_write_t read_pclta(struct inode*, struct file *dev_file, char * buffer, count_t count) { struct pclta_device *device = dev_file->private_data; struct pclta_packet * packet_buffer; byte temp_swap=0; CALL_MSG("Starting read_pclta()", ++pclta_call_level ); // verification if( device == NULL ) { RETURN_MSG("read_pclta() ENXIO", pclta_call_level-- ); return -ENXIO; } // if (last_packet_read_complete==true) // wait for uplink packet packet_buffer = device->rx->tail; // read from tail. print_buffer(device->rx); // no data available if( ! packet_buffer->busy && (dev_file->f_flags & O_NONBLOCK) ) { RETURN_MSG("read_pclta() EWOULDBLOCK", pclta_call_level-- ); return -EWOULDBLOCK; } else if( ! packet_buffer->busy ) { DEBUG_MSG( "in read_pclta() packet_buffer ADDY(tail)=%ud", (unsigned int) &packet_buffer); DEBUG_MSG("p_b->length= %d ;data0=; %x data1= %x ", packet_buffer->length,packet_buffer->data[0],packet_buffer->data[1]); RETURN_MSG("read_pclta() ENODATA", pclta_call_level-- ); return -ENODATA; // nothing available } // check if enough space available to read. if( count <= packet_buffer->length ) { DEBUG_MSG("ERROR: count= %d ; packet_buffer->length= %d",(int) count, packet_buffer->length); RETURN_MSG("read_pclta() EINVAL; count > packet_buffer->length", pclta_call_level-- ); return -EINVAL; } //swap the first two bytes and subtract one from the length temp_swap=packet_buffer->data[0]-1; // subtract one from length packet_buffer->data[0]=packet_buffer->data[1]; packet_buffer->data[1]=temp_swap; // copy data from buffer to user space copy_to_user( buffer, &packet_buffer->data[0], packet_buffer->length+1 ); // update buffer data packet_buffer->busy = false; device->rx->tail = packet_buffer->next; // restart uplink if backed off if( device->restart_uplink ) { disable_irq( device->interrupt ); device->restart_uplink = false; if( device->state == Idle ) pclta_service( device ); enable_irq( device->interrupt ); } // restart uplink, but only if device is in the Idle State RETURN_MSG("SUCCESS read_pclta() length = %d", pclta_call_level--, packet_buffer->length ); return packet_buffer->length+1; }
//int write_pclta( struct file *file, const char *buffer, size_t count, loff_t * offset) ssize_t write_pclta( struct file *file, const char *buffer, size_t count, loff_t *offset ) { struct pclta_device *device = file->private_data; struct pclta_packet *packet_buffer; unsigned int length_of_msg; byte temp_swap=0; byte temp_buffer[512]; int sum_sent=0; // sum of bytes sent. byte *msg_ptr; CALL_MSG("Starting write_pclta()", ++pclta_call_level); // verification if( device == NULL ) { RETURN_MSG("write_pclta() ERROR device=NULL", pclta_call_level-- ); return -ENXIO; } if( 0 > verify_area( VERIFY_READ, buffer, count ) ) { RETURN_MSG("write_pclta() ERROR= EFAULT verify area ", pclta_call_level-- ); return -EFAULT; } if( count < 2 ) { RETURN_MSG("write_pclta() ERROR=EINVAL count < 2 ", pclta_call_level-- ); return -EINVAL; } // length=count; // karl // copy_from_user(&packet_buffer->length, buffer, count ); // reads NI command into the legth position copy_from_user(temp_buffer, buffer,count ); // reads NI command into the legth position msg_ptr=temp_buffer; while (sum_sent < count) // must send all data { // wait for free buffer entry packet_buffer = device->tx->head; // no buffer available if( packet_buffer->busy && (file->f_flags & O_NONBLOCK) ) { RETURN_MSG("write_pclta() ERROR write_pclta()", pclta_call_level-- ); return -EWOULDBLOCK; } else if( packet_buffer->busy ) { RETURN_MSG("write_pclta() ERROR EAGAIN", pclta_call_level-- ); return -EAGAIN; // retry later } length_of_msg=*(msg_ptr+1)+2; memcpy(&packet_buffer->length,msg_ptr,length_of_msg); // DEBUG_MSG("in write_pclta() Length=[%x] D0=[%x] ;D1=[%x] ;D2=[%x] ;D3=[%x] ;D4=[%x] ;D5=[%x] ;D6=[%x]",packet_buffer->length,packet_buffer->data[0],packet_buffer->data[1],packet_buffer->data[2],packet_buffer->data[3],packet_buffer->data[4],packet_buffer->data[5],packet_buffer->data[6]); //swap the first two bytes and subtract one from the length temp_swap=packet_buffer->data[0]; // [0] is the length packet_buffer->data[0]=packet_buffer->length; // put the NI command at postion 0 packet_buffer->length=temp_swap + 1; // DEBUG_MSG("write_pclta() FIX Length=[%x] D0=[%x] ;D1=[%x] ;D2=[%x] ;D3=[%x] ;D4=[%x] ;D5=[%x] ;D6=[%x]",packet_buffer->length,packet_buffer->data[0],packet_buffer->data[1],packet_buffer->data[2],packet_buffer->data[3],packet_buffer->data[4],packet_buffer->data[5],packet_buffer->data[6]); // update output buffers and start downlink transfer device->tx->head = packet_buffer->next; packet_buffer->busy = true; sum_sent+=length_of_msg; msg_ptr+=length_of_msg; } if( device->state == Idle ) { disable_irq( device->interrupt ); DEBUG_MSG("in write_pclta() about to start_downlink interupt= %d",device->interrupt); pclta_start_downlink( device ); enable_irq( device->interrupt ); } RETURN_MSG("write_pclta() finished. ", pclta_call_level-- ); return count; }