1/2 Maple: Update bus driver to allow support of VMU device]
Subsystems (2)
PATCH 1/1 1/2 Maple: Update bus driver to allow support of VMU device]
These patches update the maple bus driver with a semaphore to allow other maple drivers to inject arbitrary packets (eg block reads and writes) into the maple bus packet stream - so allowing support for the VMU (and, eventually, other maple devices).
The patches also ensure that the maple bus driver properly supports the device model through probing.
Signed-off-by Adrian McMenamin <[email protected]>
---
drivers/sh/maple/maple.c +73 -40
@@ -47,13 +47,14 @@ static LIST_HEAD(maple_waitq);static LIST_HEAD (maple_sentq);static DEFINE_MUTEX (maple_list_lock); +static DEFINE_MUTEX (maple_wlist_lock);static struct maple_driver maple_dummy_driver;static struct device maple_bus;static int subdevice_map[MAPLE_PORTS ];static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;static unsigned long maple_pnp_time; -static int started, scanning, liststatus, fullscan; +static int started, scanning, fullscan;static struct kmem_cache *maple_queue_cache;struct maple_device_specify {
@@ -135,9 +136,9 @@ static void maple_release_device(struct device *dev)*/ void maple_add_packet (struct mapleq *mq) { -mutex_lock (&maple_list_lock); +mutex_lock (&maple_wlist_lock);list_add (&mq->list, &maple_waitq); -mutex_unlock (&maple_list_lock); +mutex_unlock (&maple_wlist_lock); }EXPORT_SYMBOL_GPL (maple_add_packet);
@@ -147,17 +148,21 @@ static struct mapleq *maple_allocq(struct maple_device *mdev) mq =kmalloc (sizeof (*mq),GFP_KERNEL );if (!mq) -return NULL ; + goto failed_nomem; mq->dev = mdev; mq->recvbufdcsp =kmem_cache_zalloc (maple_queue_cache,GFP_KERNEL ); mq->recvbuf = (void *)P2SEGADDR (mq->recvbufdcsp); -if (!mq->recvbuf) { -kfree (mq); -return NULL ; - } +if (!mq->recvbuf) + goto failed_p2; +init_MUTEX (&mq->sem);return mq; + +failed_p2: +kfree (mq); +failed_nomem: +return NULL ; }static struct maple_device *maple_alloc_dev (int port,int unit)
@@ -178,7 +183,6 @@ static struct maple_device *maple_alloc_dev(int port, int unit) } mdev->dev.bus = &maple_bus_type; mdev->dev.parent = &maple_bus; - mdev->function =0 ;return mdev; }
@@ -216,8 +220,7 @@ static void maple_build_block(struct mapleq *mq) *maple_sendptr++ =PHYSADDR (mq->recvbuf); *maple_sendptr++ = mq->command | (to <<8 ) | (from <<16 ) | (len <<24 ); - -while (len-- >0 ) +while (len-- >0 ) *maple_sendptr++ = *lsendbuf++; }
@@ -230,16 +233,24 @@ static void maple_send(void)if (!list_empty (&maple_sentq))return ; -if (list_empty (&maple_waitq) || !maple_dma_done ()) +mutex_lock (&maple_wlist_lock); +if (list_empty (&maple_waitq) || !maple_dma_done ()) { +mutex_unlock (&maple_wlist_lock);return ; + } +mutex_unlock (&maple_wlist_lock); maple_packets =0 ; maple_sendptr = maple_lastptr = maple_sendbuf; -list_for_each_entry_safe (mq, nmq, &maple_waitq, list) { +mutex_lock (&maple_list_lock); +mutex_lock (&maple_wlist_lock); +list_for_each_entry_safe (mq, nmq, &maple_waitq, list) {maple_build_block (mq);list_move (&mq->list, &maple_sentq); -if (maple_packets++ >MAPLE_MAXPACKETS ) +if (maple_packets++ >MAPLE_MAXPACKETS )break ; } +mutex_unlock (&maple_wlist_lock); +mutex_unlock (&maple_list_lock);if (maple_packets >0 ) {for (i =0 ; i < (1 <<MAPLE_DMA_PAGES ); i++) dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
@@ -247,7 +258,8 @@ static void maple_send(void) } } -static int attach_matching_maple_driver (struct device_driver *driver, +/* check if there is a driver registered likely to match this device */ +static int check_matching_maple_driver (struct device_driver *driver,void *devptr) {struct maple_driver *maple_drv;
@@ -255,12 +267,8 @@ static int attach_matching_maple_driver(struct device_driver *driver, mdev = devptr; maple_drv =to_maple_driver (driver); -if (mdev->devinfo.function &be32_to_cpu (maple_drv->function)) { -if (maple_drv->connect (mdev) ==0 ) { - mdev->driver = maple_drv; -return 1 ; - } - } +if (mdev->devinfo.function &cpu_to_be32 (maple_drv->function)) +return 1 ;return 0 ; }
@@ -268,11 +276,6 @@ static void maple_detach_driver(struct maple_device *mdev) {if (!mdev)return ; -if (mdev->driver) { -if (mdev->driver->disconnect) - mdev->driver->disconnect (mdev); - } - mdev->driver =NULL ;device_unregister (&mdev->dev); mdev =NULL ; }
@@ -328,8 +331,8 @@ static void maple_attach_driver(struct maple_device *mdev) mdev->port, mdev->unit, function); matched = - bus_for_each_drv(&maple_bus_type, NULL, mdev, - attach_matching_maple_driver); + bus_for_each_drv(&maple_bus_type, NULL, mdev, + check_matching_maple_driver);if (matched ==0 ) {/* Driver does not exist yet */
@@ -342,7 +345,7 @@ static void maple_attach_driver(struct maple_device *mdev) } mdev->function = function; mdev->dev.release = &maple_release_device; - retval =device_register (&mdev->dev); + retval =device_register (&mdev->dev);if (retval) {printk (KERN_INFO "Maple bus: Attempt to register device"
@@ -377,18 +380,20 @@ static int setup_maple_commands(struct device *device, void *ignored)if ((maple_dev->interval >0 ) &&time_after (jiffies, maple_dev->when)) { +if (down_trylock (&maple_dev->mq->sem)) +return 0 ; maple_dev->when = jiffies + maple_dev->interval; maple_dev->mq->command =MAPLE_COMMAND_GETCOND ; maple_dev->mq->sendbuf = &maple_dev->function; maple_dev->mq->length =1 ;maple_add_packet (maple_dev->mq); - liststatus++; }else {if (time_after (jiffies, maple_pnp_time)) { +if (down_trylock (&maple_dev->mq->sem)) +return -1 ; maple_dev->mq->command =MAPLE_COMMAND_DEVINFO ; maple_dev->mq->length =0 ;maple_add_packet (maple_dev->mq); - liststatus++; } }
@@ -398,32 +403,38 @@ static int setup_maple_commands(struct device *device, void *ignored)/* VBLANK bottom half - implemented via workqueue */ static void maple_vblank_handler (struct work_struct *work) { -if (!maple_dma_done ()) -return ;if (!list_empty (&maple_sentq))return ; +if (!maple_dma_done ()) +return ;ctrl_outl (0 ,MAPLE_ENABLE ); - liststatus =0 ;bus_for_each_dev (&maple_bus_type,NULL ,NULL , setup_maple_commands);if (time_after (jiffies, maple_pnp_time)) maple_pnp_time = jiffies +MAPLE_PNP_INTERVAL ; -if (liststatus &&list_empty (&maple_sentq)) { +mutex_lock (&maple_wlist_lock); +if (!list_empty (&maple_waitq) &&list_empty (&maple_sentq)) { +mutex_unlock (&maple_wlist_lock); +mutex_lock (&maple_list_lock);INIT_LIST_HEAD (&maple_sentq); +mutex_unlock (&maple_list_lock);maple_send (); + }else { +mutex_unlock (&maple_wlist_lock); } +maplebus_dma_reset (); }/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ static void maple_map_subunits (struct maple_device *mdev,int submask) { -int retval, k, devcheck; +int retval, k, devcheck, locking;struct maple_device *mdev_add;struct maple_device_specify ds; + ds.port = mdev->port;for (k =0 ; k <5 ; k++) { - ds.port = mdev->port; ds.unit = k +1 ; retval = bus_for_each_dev(&maple_bus_type, NULL, &ds,
@@ -437,9 +448,15 @@ static void maple_map_subunits(struct maple_device *mdev, int submask) mdev_add =maple_alloc_dev (mdev->port, k +1 );if (!mdev_add)return ; + locking =down_trylock (&mdev_add->mq->sem); +if (locking) { +up (&mdev_add->mq->sem); +down_interruptible (&mdev_add->mq->sem); + } mdev_add->mq->command =MAPLE_COMMAND_DEVINFO ; mdev_add->mq->length =0 ;maple_add_packet (mdev_add->mq); +/* mark that we are checking sub devices */ scanning =1 ; } submask = submask >>1 ;
@@ -512,15 +529,17 @@ static void maple_dma_handler(struct work_struct *work)struct maple_device *dev;char *recvbuf;enum maple_code code; -int i; +int i, locking;if (!maple_dma_done ())return ;ctrl_outl (0 ,MAPLE_ENABLE ); +mutex_lock (&maple_list_lock);if (!list_empty (&maple_sentq)) {list_for_each_entry_safe (mq, nmq, &maple_sentq, list) { recvbuf = mq->recvbuf; code = recvbuf[0 ]; +up (&mq->sem); dev = mq->dev;switch (code) {case MAPLE_RESPONSE_NONE :
@@ -559,18 +578,26 @@ static void maple_dma_handler(struct work_struct *work) } }INIT_LIST_HEAD (&maple_sentq); +mutex_unlock (&maple_list_lock); +/* if scanning is 1 then we have subdevices to check */ if (scanning ==1 ) {maple_send (); scanning =2 ; }else scanning =0 ; - +/*check if we have actually tested all ports yet */ if (!fullscan) { fullscan =1 ;for (i =0 ; i <MAPLE_PORTS ; i++) {if (checked[i] == false) { fullscan =0 ; dev = baseunits[i]; + locking =down_trylock (&dev->mq->sem); +if (locking) { +up (&dev->mq->sem); +down_interruptible + (&dev->mq->sem); + } dev->mq->command =MAPLE_COMMAND_DEVINFO ; dev->mq->length =0 ;
@@ -578,8 +605,11 @@ static void maple_dma_handler(struct work_struct *work) } } } +/* mark that we have been through the first scan */ if (started ==0 ) started =1 ; + }else { +mutex_unlock (&maple_list_lock); }maplebus_dma_reset (); }
@@ -631,7 +661,7 @@ static int match_maple_bus_driver(struct device *devptr,if (maple_dev->devinfo.function ==0xFFFFFFFF )return 0 ;else if (maple_dev->devinfo.function & -be32_to_cpu (maple_drv->function)) +cpu_to_be32 (maple_drv->function))return 1 ;return 0 ; }
@@ -713,6 +743,8 @@ static int __init maple_bus_init(void)if (!maple_queue_cache) goto cleanup_bothirqs; +INIT_LIST_HEAD (&maple_waitq); +/* setup maple ports */ for (i =0 ; i <MAPLE_PORTS ; i++) { checked[i] = false;
@@ -723,6 +755,7 @@ static int __init maple_bus_init(void)maple_free_dev (mdev[i]); goto cleanup_cache; } +down_interruptible (&mdev[i]->mq->sem); mdev[i]->mq->command =MAPLE_COMMAND_DEVINFO ; mdev[i]->mq->length =0 ;maple_add_packet (mdev[i]->mq);
include/linux/maple.h +2 -0
@@ -33,6 +33,7 @@ struct mapleq {void *sendbuf, *recvbuf, *recvbufdcsp;unsigned char length;enum maple_code command; +struct semaphore sem; };struct maple_devinfo {
@@ -73,6 +74,7 @@ void maple_getcond_callback(struct maple_device *dev,int maple_driver_register (struct device_driver *drv);void maple_add_packet (struct mapleq *mq); +#define to_maple_dev (n) container_of(n, struct maple_device, dev)#define to_maple_driver (n) container_of(n, struct maple_driver, drv)